1674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen/* 2674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * Copyright 2003,2004 The Apache Software Foundation 3674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * 4674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * Licensed under the Apache License, Version 2.0 (the "License"); 5674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * you may not use this file except in compliance with the License. 6674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * You may obtain a copy of the License at 7674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * 8674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * http://www.apache.org/licenses/LICENSE-2.0 9674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * 10674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * Unless required by applicable law or agreed to in writing, software 11674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * distributed under the License is distributed on an "AS IS" BASIS, 12674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * See the License for the specific language governing permissions and 14674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * limitations under the License. 15674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen */ 16674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenpackage org.mockito.cglib.beans; 17674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 18674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport java.beans.PropertyDescriptor; 19674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport java.lang.reflect.*; 20674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 21674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.asm.ClassVisitor; 22674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.asm.Type; 23674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.cglib.core.*; 24674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 25674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport java.util.*; 26674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 27674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen/** 28674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @author Chris Nokleberg 29674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen */ 30674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenabstract public class BeanCopier 31674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen{ 32674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen private static final BeanCopierKey KEY_FACTORY = 33674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen (BeanCopierKey)KeyFactory.create(BeanCopierKey.class); 34674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen private static final Type CONVERTER = 35674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen TypeUtils.parseType("org.mockito.cglib.core.Converter"); 36674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen private static final Type BEAN_COPIER = 37674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen TypeUtils.parseType("org.mockito.cglib.beans.BeanCopier"); 38674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen private static final Signature COPY = 39674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen new Signature("copy", Type.VOID_TYPE, new Type[]{ Constants.TYPE_OBJECT, Constants.TYPE_OBJECT, CONVERTER }); 40674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen private static final Signature CONVERT = 41674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen TypeUtils.parseSignature("Object convert(Object, Class, Object)"); 42674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 43674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen interface BeanCopierKey { 44674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public Object newInstance(String source, String target, boolean useConverter); 45674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 46674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 47674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public static BeanCopier create(Class source, Class target, boolean useConverter) { 48674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen Generator gen = new Generator(); 49674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen gen.setSource(source); 50674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen gen.setTarget(target); 51674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen gen.setUseConverter(useConverter); 52674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen return gen.create(); 53674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 54674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 55674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen abstract public void copy(Object from, Object to, Converter converter); 56674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 57674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public static class Generator extends AbstractClassGenerator { 58674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen private static final Source SOURCE = new Source(BeanCopier.class.getName()); 59674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen private Class source; 60674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen private Class target; 61674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen private boolean useConverter; 62674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 63674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public Generator() { 64674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen super(SOURCE); 65674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 66674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 67674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public void setSource(Class source) { 68674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen if(!Modifier.isPublic(source.getModifiers())){ 69674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen setNamePrefix(source.getName()); 70674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 71674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen this.source = source; 72674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 73674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 74674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public void setTarget(Class target) { 75674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen if(!Modifier.isPublic(target.getModifiers())){ 76674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen setNamePrefix(target.getName()); 77674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 78674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 79674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen this.target = target; 80674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 81674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 82674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public void setUseConverter(boolean useConverter) { 83674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen this.useConverter = useConverter; 84674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 85674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 86674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen protected ClassLoader getDefaultClassLoader() { 87674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen return source.getClassLoader(); 88674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 89674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 90674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public BeanCopier create() { 91674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen Object key = KEY_FACTORY.newInstance(source.getName(), target.getName(), useConverter); 92674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen return (BeanCopier)super.create(key); 93674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 94674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 95674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public void generateClass(ClassVisitor v) { 96674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen Type sourceType = Type.getType(source); 97674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen Type targetType = Type.getType(target); 98674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen ClassEmitter ce = new ClassEmitter(v); 99674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen ce.begin_class(Constants.V1_2, 100674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen Constants.ACC_PUBLIC, 101674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen getClassName(), 102674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen BEAN_COPIER, 103674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen null, 104674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen Constants.SOURCE_FILE); 105674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 106674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen EmitUtils.null_constructor(ce); 107674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, COPY, null); 108674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen PropertyDescriptor[] getters = ReflectUtils.getBeanGetters(source); 109674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen PropertyDescriptor[] setters = ReflectUtils.getBeanGetters(target); 110674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 111674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen Map names = new HashMap(); 112674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen for (int i = 0; i < getters.length; i++) { 113674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen names.put(getters[i].getName(), getters[i]); 114674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 115674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen Local targetLocal = e.make_local(); 116674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen Local sourceLocal = e.make_local(); 117674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen if (useConverter) { 118674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.load_arg(1); 119674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.checkcast(targetType); 120674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.store_local(targetLocal); 121674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.load_arg(0); 122674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.checkcast(sourceType); 123674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.store_local(sourceLocal); 124674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } else { 125674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.load_arg(1); 126674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.checkcast(targetType); 127674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.load_arg(0); 128674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.checkcast(sourceType); 129674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 130674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen for (int i = 0; i < setters.length; i++) { 131674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen PropertyDescriptor setter = setters[i]; 132674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen PropertyDescriptor getter = (PropertyDescriptor)names.get(setter.getName()); 133674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen if (getter != null) { 134674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen MethodInfo read = ReflectUtils.getMethodInfo(getter.getReadMethod()); 135674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen MethodInfo write = ReflectUtils.getMethodInfo(setter.getWriteMethod()); 136674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen if (useConverter) { 137674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen Type setterType = write.getSignature().getArgumentTypes()[0]; 138674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.load_local(targetLocal); 139674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.load_arg(2); 140674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.load_local(sourceLocal); 141674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.invoke(read); 142674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.box(read.getSignature().getReturnType()); 143674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen EmitUtils.load_class(e, setterType); 144674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.push(write.getSignature().getName()); 145674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.invoke_interface(CONVERTER, CONVERT); 146674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.unbox_or_zero(setterType); 147674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.invoke(write); 148674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } else if (compatible(getter, setter)) { 149674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.dup2(); 150674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.invoke(read); 151674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.invoke(write); 152674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 153674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 154674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 155674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.return_value(); 156674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.end_method(); 157674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen ce.end_class(); 158674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 159674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 160674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen private static boolean compatible(PropertyDescriptor getter, PropertyDescriptor setter) { 161674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen // TODO: allow automatic widening conversions? 162674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen return setter.getPropertyType().isAssignableFrom(getter.getPropertyType()); 163674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 164674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 165674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen protected Object firstInstance(Class type) { 166674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen return ReflectUtils.newInstance(type); 167674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 168674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 169674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen protected Object nextInstance(Object instance) { 170674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen return instance; 171674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 172674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 173674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen} 174