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