BulkBeanEmitter.java revision 674060f01e9090cd21b3c5656cc3204912ad17a6
1/* 2 * Copyright 2003,2004 The Apache Software Foundation 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16package org.mockito.cglib.beans; 17 18import java.lang.reflect.Constructor; 19import java.lang.reflect.Method; 20import java.lang.reflect.Modifier; 21import java.util.*; 22 23import org.mockito.asm.ClassVisitor; 24import org.mockito.asm.Type; 25import org.mockito.cglib.core.*; 26 27class BulkBeanEmitter extends ClassEmitter { 28 private static final Signature GET_PROPERTY_VALUES = 29 TypeUtils.parseSignature("void getPropertyValues(Object, Object[])"); 30 private static final Signature SET_PROPERTY_VALUES = 31 TypeUtils.parseSignature("void setPropertyValues(Object, Object[])"); 32 private static final Signature CSTRUCT_EXCEPTION = 33 TypeUtils.parseConstructor("Throwable, int"); 34 private static final Type BULK_BEAN = 35 TypeUtils.parseType("org.mockito.cglib.beans.BulkBean"); 36 private static final Type BULK_BEAN_EXCEPTION = 37 TypeUtils.parseType("org.mockito.cglib.beans.BulkBeanException"); 38 39 public BulkBeanEmitter(ClassVisitor v, 40 String className, 41 Class target, 42 String[] getterNames, 43 String[] setterNames, 44 Class[] types) { 45 super(v); 46 47 Method[] getters = new Method[getterNames.length]; 48 Method[] setters = new Method[setterNames.length]; 49 validate(target, getterNames, setterNames, types, getters, setters); 50 51 begin_class(Constants.V1_2, Constants.ACC_PUBLIC, className, BULK_BEAN, null, Constants.SOURCE_FILE); 52 EmitUtils.null_constructor(this); 53 generateGet(target, getters); 54 generateSet(target, setters); 55 end_class(); 56 } 57 58 private void generateGet(final Class target, final Method[] getters) { 59 CodeEmitter e = begin_method(Constants.ACC_PUBLIC, GET_PROPERTY_VALUES, null); 60 if (getters.length >= 0) { 61 e.load_arg(0); 62 e.checkcast(Type.getType(target)); 63 Local bean = e.make_local(); 64 e.store_local(bean); 65 for (int i = 0; i < getters.length; i++) { 66 if (getters[i] != null) { 67 MethodInfo getter = ReflectUtils.getMethodInfo(getters[i]); 68 e.load_arg(1); 69 e.push(i); 70 e.load_local(bean); 71 e.invoke(getter); 72 e.box(getter.getSignature().getReturnType()); 73 e.aastore(); 74 } 75 } 76 } 77 e.return_value(); 78 e.end_method(); 79 } 80 81 private void generateSet(final Class target, final Method[] setters) { 82 // setPropertyValues 83 CodeEmitter e = begin_method(Constants.ACC_PUBLIC, SET_PROPERTY_VALUES, null); 84 if (setters.length > 0) { 85 Local index = e.make_local(Type.INT_TYPE); 86 e.push(0); 87 e.store_local(index); 88 e.load_arg(0); 89 e.checkcast(Type.getType(target)); 90 e.load_arg(1); 91 Block handler = e.begin_block(); 92 int lastIndex = 0; 93 for (int i = 0; i < setters.length; i++) { 94 if (setters[i] != null) { 95 MethodInfo setter = ReflectUtils.getMethodInfo(setters[i]); 96 int diff = i - lastIndex; 97 if (diff > 0) { 98 e.iinc(index, diff); 99 lastIndex = i; 100 } 101 e.dup2(); 102 e.aaload(i); 103 e.unbox(setter.getSignature().getArgumentTypes()[0]); 104 e.invoke(setter); 105 } 106 } 107 handler.end(); 108 e.return_value(); 109 e.catch_exception(handler, Constants.TYPE_THROWABLE); 110 e.new_instance(BULK_BEAN_EXCEPTION); 111 e.dup_x1(); 112 e.swap(); 113 e.load_local(index); 114 e.invoke_constructor(BULK_BEAN_EXCEPTION, CSTRUCT_EXCEPTION); 115 e.athrow(); 116 } else { 117 e.return_value(); 118 } 119 e.end_method(); 120 } 121 122 private static void validate(Class target, 123 String[] getters, 124 String[] setters, 125 Class[] types, 126 Method[] getters_out, 127 Method[] setters_out) { 128 int i = -1; 129 if (setters.length != types.length || getters.length != types.length) { 130 throw new BulkBeanException("accessor array length must be equal type array length", i); 131 } 132 try { 133 for (i = 0; i < types.length; i++) { 134 if (getters[i] != null) { 135 Method method = ReflectUtils.findDeclaredMethod(target, getters[i], null); 136 if (method.getReturnType() != types[i]) { 137 throw new BulkBeanException("Specified type " + types[i] + 138 " does not match declared type " + method.getReturnType(), i); 139 } 140 if (Modifier.isPrivate(method.getModifiers())) { 141 throw new BulkBeanException("Property is private", i); 142 } 143 getters_out[i] = method; 144 } 145 if (setters[i] != null) { 146 Method method = ReflectUtils.findDeclaredMethod(target, setters[i], new Class[]{ types[i] }); 147 if (Modifier.isPrivate(method.getModifiers()) ){ 148 throw new BulkBeanException("Property is private", i); 149 } 150 setters_out[i] = method; 151 } 152 } 153 } catch (NoSuchMethodException e) { 154 throw new BulkBeanException("Cannot find specified property", i); 155 } 156 } 157} 158