BeanGenerator.java revision 674060f01e9090cd21b3c5656cc3204912ad17a6
1/*
2 * Copyright 2003 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.beans.PropertyDescriptor;
19import java.util.*;
20
21import org.mockito.asm.ClassVisitor;
22import org.mockito.asm.Type;
23import org.mockito.cglib.core.*;
24
25/**
26 * @author Juozas Baliuka, Chris Nokleberg
27 */
28public class BeanGenerator extends AbstractClassGenerator
29{
30    private static final Source SOURCE = new Source(BeanGenerator.class.getName());
31    private static final BeanGeneratorKey KEY_FACTORY =
32      (BeanGeneratorKey)KeyFactory.create(BeanGeneratorKey.class);
33
34    interface BeanGeneratorKey {
35        public Object newInstance(String superclass, Map props);
36    }
37
38    private Class superclass;
39    private Map props = new HashMap();
40    private boolean classOnly;
41
42    public BeanGenerator() {
43        super(SOURCE);
44    }
45
46    /**
47     * Set the class which the generated class will extend. The class
48     * must not be declared as final, and must have a non-private
49     * no-argument constructor.
50     * @param superclass class to extend, or null to extend Object
51     */
52    public void setSuperclass(Class superclass) {
53        if (superclass != null && superclass.equals(Object.class)) {
54            superclass = null;
55        }
56        this.superclass = superclass;
57    }
58
59    public void addProperty(String name, Class type) {
60        if (props.containsKey(name)) {
61            throw new IllegalArgumentException("Duplicate property name \"" + name + "\"");
62        }
63        props.put(name, Type.getType(type));
64    }
65
66    protected ClassLoader getDefaultClassLoader() {
67        if (superclass != null) {
68            return superclass.getClassLoader();
69        } else {
70            return null;
71        }
72    }
73
74    public Object create() {
75        classOnly = false;
76        return createHelper();
77    }
78
79    public Object createClass() {
80        classOnly = true;
81        return createHelper();
82    }
83
84    private Object createHelper() {
85        if (superclass != null) {
86            setNamePrefix(superclass.getName());
87        }
88        String superName = (superclass != null) ? superclass.getName() : "java.lang.Object";
89        Object key = KEY_FACTORY.newInstance(superName, props);
90        return super.create(key);
91    }
92
93    public void generateClass(ClassVisitor v) throws Exception {
94        int size = props.size();
95        String[] names = (String[])props.keySet().toArray(new String[size]);
96        Type[] types = new Type[size];
97        for (int i = 0; i < size; i++) {
98            types[i] = (Type)props.get(names[i]);
99        }
100        ClassEmitter ce = new ClassEmitter(v);
101        ce.begin_class(Constants.V1_2,
102                       Constants.ACC_PUBLIC,
103                       getClassName(),
104                       superclass != null ? Type.getType(superclass) : Constants.TYPE_OBJECT,
105                       null,
106                       null);
107        EmitUtils.null_constructor(ce);
108        EmitUtils.add_properties(ce, names, types);
109        ce.end_class();
110    }
111
112    protected Object firstInstance(Class type) {
113        if (classOnly) {
114            return type;
115        } else {
116            return ReflectUtils.newInstance(type);
117        }
118    }
119
120    protected Object nextInstance(Object instance) {
121        Class protoclass = (instance instanceof Class) ? (Class)instance : instance.getClass();
122        if (classOnly) {
123            return protoclass;
124        } else {
125            return ReflectUtils.newInstance(protoclass);
126        }
127    }
128
129    public static void addProperties(BeanGenerator gen, Map props) {
130        for (Iterator it = props.keySet().iterator(); it.hasNext();) {
131            String name = (String)it.next();
132            gen.addProperty(name, (Class)props.get(name));
133        }
134    }
135
136    public static void addProperties(BeanGenerator gen, Class type) {
137        addProperties(gen, ReflectUtils.getBeanProperties(type));
138    }
139
140    public static void addProperties(BeanGenerator gen, PropertyDescriptor[] descriptors) {
141        for (int i = 0; i < descriptors.length; i++) {
142            gen.addProperty(descriptors[i].getName(), descriptors[i].getPropertyType());
143        }
144    }
145}
146