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  */
16 package org.mockito.cglib.reflect;
17 
18 import java.lang.reflect.*;
19 
20 import org.mockito.asm.ClassVisitor;
21 import org.mockito.asm.Type;
22 import org.mockito.cglib.core.*;
23 
24 /**
25  * @author Chris Nokleberg
26  * @version $Id: ConstructorDelegate.java,v 1.20 2006/03/05 02:43:19 herbyderby Exp $
27  */
28 abstract public class ConstructorDelegate {
29     private static final ConstructorKey KEY_FACTORY =
30       (ConstructorKey)KeyFactory.create(ConstructorKey.class, KeyFactory.CLASS_BY_NAME);
31 
32     interface ConstructorKey {
newInstance(String declaring, String iface)33         public Object newInstance(String declaring, String iface);
34     }
35 
ConstructorDelegate()36     protected ConstructorDelegate() {
37     }
38 
create(Class targetClass, Class iface)39     public static ConstructorDelegate create(Class targetClass, Class iface) {
40         Generator gen = new Generator();
41         gen.setTargetClass(targetClass);
42         gen.setInterface(iface);
43         return gen.create();
44     }
45 
46     public static class Generator extends AbstractClassGenerator {
47         private static final Source SOURCE = new Source(ConstructorDelegate.class.getName());
48         private static final Type CONSTRUCTOR_DELEGATE =
49           TypeUtils.parseType("org.mockito.cglib.reflect.ConstructorDelegate");
50 
51         private Class iface;
52         private Class targetClass;
53 
Generator()54         public Generator() {
55             super(SOURCE);
56         }
57 
setInterface(Class iface)58         public void setInterface(Class iface) {
59             this.iface = iface;
60         }
61 
setTargetClass(Class targetClass)62         public void setTargetClass(Class targetClass) {
63             this.targetClass = targetClass;
64         }
65 
create()66         public ConstructorDelegate create() {
67             setNamePrefix(targetClass.getName());
68             Object key = KEY_FACTORY.newInstance(iface.getName(), targetClass.getName());
69             return (ConstructorDelegate)super.create(key);
70         }
71 
getDefaultClassLoader()72         protected ClassLoader getDefaultClassLoader() {
73             return targetClass.getClassLoader();
74         }
75 
generateClass(ClassVisitor v)76         public void generateClass(ClassVisitor v) {
77             setNamePrefix(targetClass.getName());
78 
79             final Method newInstance = ReflectUtils.findNewInstance(iface);
80             if (!newInstance.getReturnType().isAssignableFrom(targetClass)) {
81                 throw new IllegalArgumentException("incompatible return type");
82             }
83             final Constructor constructor;
84             try {
85                 constructor = targetClass.getDeclaredConstructor(newInstance.getParameterTypes());
86             } catch (NoSuchMethodException e) {
87                 throw new IllegalArgumentException("interface does not match any known constructor");
88             }
89 
90             ClassEmitter ce = new ClassEmitter(v);
91             ce.begin_class(Constants.V1_2,
92                            Constants.ACC_PUBLIC,
93                            getClassName(),
94                            CONSTRUCTOR_DELEGATE,
95                            new Type[]{ Type.getType(iface) },
96                            Constants.SOURCE_FILE);
97             Type declaring = Type.getType(constructor.getDeclaringClass());
98             EmitUtils.null_constructor(ce);
99             CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC,
100                                             ReflectUtils.getSignature(newInstance),
101                                             ReflectUtils.getExceptionTypes(newInstance));
102             e.new_instance(declaring);
103             e.dup();
104             e.load_args();
105             e.invoke_constructor(declaring, ReflectUtils.getSignature(constructor));
106             e.return_value();
107             e.end_method();
108             ce.end_class();
109         }
110 
firstInstance(Class type)111         protected Object firstInstance(Class type) {
112             return ReflectUtils.newInstance(type);
113         }
114 
nextInstance(Object instance)115         protected Object nextInstance(Object instance) {
116             return instance;
117         }
118     }
119 }
120