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.*; 19674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport java.util.*; 20674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 21674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.asm.ClassVisitor; 22674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.asm.Label; 23674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.asm.Type; 24674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.cglib.core.*; 25674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 26674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenclass BeanMapEmitter extends ClassEmitter { 27674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen private static final Type BEAN_MAP = 28674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen TypeUtils.parseType("org.mockito.cglib.beans.BeanMap"); 29674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen private static final Type FIXED_KEY_SET = 30674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen TypeUtils.parseType("org.mockito.cglib.beans.FixedKeySet"); 31674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen private static final Signature CSTRUCT_OBJECT = 32674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen TypeUtils.parseConstructor("Object"); 33674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen private static final Signature CSTRUCT_STRING_ARRAY = 34674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen TypeUtils.parseConstructor("String[]"); 35674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen private static final Signature BEAN_MAP_GET = 36674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen TypeUtils.parseSignature("Object get(Object, Object)"); 37674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen private static final Signature BEAN_MAP_PUT = 38674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen TypeUtils.parseSignature("Object put(Object, Object, Object)"); 39674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen private static final Signature KEY_SET = 40674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen TypeUtils.parseSignature("java.util.Set keySet()"); 41674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen private static final Signature NEW_INSTANCE = 42674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen new Signature("newInstance", BEAN_MAP, new Type[]{ Constants.TYPE_OBJECT }); 43674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen private static final Signature GET_PROPERTY_TYPE = 44674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen TypeUtils.parseSignature("Class getPropertyType(String)"); 45674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 46674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public BeanMapEmitter(ClassVisitor v, String className, Class type, int require) { 47674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen super(v); 48674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 49674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen begin_class(Constants.V1_2, Constants.ACC_PUBLIC, className, BEAN_MAP, null, Constants.SOURCE_FILE); 50674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen EmitUtils.null_constructor(this); 51674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen EmitUtils.factory_method(this, NEW_INSTANCE); 52674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen generateConstructor(); 53674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 54674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen Map getters = makePropertyMap(ReflectUtils.getBeanGetters(type)); 55674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen Map setters = makePropertyMap(ReflectUtils.getBeanSetters(type)); 56674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen Map allProps = new HashMap(); 57674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen allProps.putAll(getters); 58674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen allProps.putAll(setters); 59674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 60674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen if (require != 0) { 61674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen for (Iterator it = allProps.keySet().iterator(); it.hasNext();) { 62674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen String name = (String)it.next(); 63674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen if ((((require & BeanMap.REQUIRE_GETTER) != 0) && !getters.containsKey(name)) || 64674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen (((require & BeanMap.REQUIRE_SETTER) != 0) && !setters.containsKey(name))) { 65674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen it.remove(); 66674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen getters.remove(name); 67674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen setters.remove(name); 68674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 69674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 70674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 71674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen generateGet(type, getters); 72674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen generatePut(type, setters); 73674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 74674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen String[] allNames = getNames(allProps); 75674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen generateKeySet(allNames); 76674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen generateGetPropertyType(allProps, allNames); 77674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen end_class(); 78674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 79674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 80674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen private Map makePropertyMap(PropertyDescriptor[] props) { 81674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen Map names = new HashMap(); 82674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen for (int i = 0; i < props.length; i++) { 83674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen names.put(((PropertyDescriptor)props[i]).getName(), props[i]); 84674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 85674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen return names; 86674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 87674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 88674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen private String[] getNames(Map propertyMap) { 89674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen return (String[])propertyMap.keySet().toArray(new String[propertyMap.size()]); 90674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 91674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 92674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen private void generateConstructor() { 93674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen CodeEmitter e = begin_method(Constants.ACC_PUBLIC, CSTRUCT_OBJECT, null); 94674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.load_this(); 95674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.load_arg(0); 96674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.super_invoke_constructor(CSTRUCT_OBJECT); 97674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.return_value(); 98674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.end_method(); 99674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 100674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 101674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen private void generateGet(Class type, final Map getters) { 102674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen final CodeEmitter e = begin_method(Constants.ACC_PUBLIC, BEAN_MAP_GET, null); 103674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.load_arg(0); 104674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.checkcast(Type.getType(type)); 105674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.load_arg(1); 106674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.checkcast(Constants.TYPE_STRING); 107674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen EmitUtils.string_switch(e, getNames(getters), Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() { 108674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public void processCase(Object key, Label end) { 109674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen PropertyDescriptor pd = (PropertyDescriptor)getters.get(key); 110674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen MethodInfo method = ReflectUtils.getMethodInfo(pd.getReadMethod()); 111674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.invoke(method); 112674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.box(method.getSignature().getReturnType()); 113674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.return_value(); 114674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 115674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public void processDefault() { 116674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.aconst_null(); 117674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.return_value(); 118674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 119674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen }); 120674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.end_method(); 121674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 122674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 123674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen private void generatePut(Class type, final Map setters) { 124674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen final CodeEmitter e = begin_method(Constants.ACC_PUBLIC, BEAN_MAP_PUT, null); 125674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.load_arg(0); 126674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.checkcast(Type.getType(type)); 127674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.load_arg(1); 128674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.checkcast(Constants.TYPE_STRING); 129674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen EmitUtils.string_switch(e, getNames(setters), Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() { 130674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public void processCase(Object key, Label end) { 131674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen PropertyDescriptor pd = (PropertyDescriptor)setters.get(key); 132674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen if (pd.getReadMethod() == null) { 133674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.aconst_null(); 134674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } else { 135674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen MethodInfo read = ReflectUtils.getMethodInfo(pd.getReadMethod()); 136674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.dup(); 137674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.invoke(read); 138674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.box(read.getSignature().getReturnType()); 139674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 140674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.swap(); // move old value behind bean 141674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.load_arg(2); // new value 142674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen MethodInfo write = ReflectUtils.getMethodInfo(pd.getWriteMethod()); 143674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.unbox(write.getSignature().getArgumentTypes()[0]); 144674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.invoke(write); 145674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.return_value(); 146674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 147674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public void processDefault() { 148674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen // fall-through 149674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 150674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen }); 151674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.aconst_null(); 152674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.return_value(); 153674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.end_method(); 154674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 155674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 156674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen private void generateKeySet(String[] allNames) { 157674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen // static initializer 158674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen declare_field(Constants.ACC_STATIC | Constants.ACC_PRIVATE, "keys", FIXED_KEY_SET, null); 159674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 160674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen CodeEmitter e = begin_static(); 161674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.new_instance(FIXED_KEY_SET); 162674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.dup(); 163674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen EmitUtils.push_array(e, allNames); 164674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.invoke_constructor(FIXED_KEY_SET, CSTRUCT_STRING_ARRAY); 165674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.putfield("keys"); 166674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.return_value(); 167674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.end_method(); 168674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 169674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen // keySet 170674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e = begin_method(Constants.ACC_PUBLIC, KEY_SET, null); 171674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.load_this(); 172674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.getfield("keys"); 173674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.return_value(); 174674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.end_method(); 175674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 176674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 177674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen private void generateGetPropertyType(final Map allProps, String[] allNames) { 178674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen final CodeEmitter e = begin_method(Constants.ACC_PUBLIC, GET_PROPERTY_TYPE, null); 179674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.load_arg(0); 180674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen EmitUtils.string_switch(e, allNames, Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() { 181674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public void processCase(Object key, Label end) { 182674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen PropertyDescriptor pd = (PropertyDescriptor)allProps.get(key); 183674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen EmitUtils.load_class(e, Type.getType(pd.getPropertyType())); 184674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.return_value(); 185674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 186674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public void processDefault() { 187674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.aconst_null(); 188674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.return_value(); 189674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 190674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen }); 191674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen e.end_method(); 192674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 193674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen} 194