1674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen/*
2674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * Copyright 2003 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.reflect;
17674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
18674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport java.lang.reflect.*;
19674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
20674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.asm.ClassVisitor;
21674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.asm.Type;
22674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.cglib.core.*;
23674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
24674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen/**
25674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @author Chris Nokleberg
26674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @version $Id: ConstructorDelegate.java,v 1.20 2006/03/05 02:43:19 herbyderby Exp $
27674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen */
28674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenabstract public class ConstructorDelegate {
29674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final ConstructorKey KEY_FACTORY =
30674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      (ConstructorKey)KeyFactory.create(ConstructorKey.class, KeyFactory.CLASS_BY_NAME);
31674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
32674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    interface ConstructorKey {
33674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        public Object newInstance(String declaring, String iface);
34674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
35674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
36674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    protected ConstructorDelegate() {
37674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
38674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
39674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static ConstructorDelegate create(Class targetClass, Class iface) {
40674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Generator gen = new Generator();
41674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        gen.setTargetClass(targetClass);
42674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        gen.setInterface(iface);
43674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        return gen.create();
44674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
45674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
46674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public static class Generator extends AbstractClassGenerator {
47674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        private static final Source SOURCE = new Source(ConstructorDelegate.class.getName());
48674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        private static final Type CONSTRUCTOR_DELEGATE =
49674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen          TypeUtils.parseType("org.mockito.cglib.reflect.ConstructorDelegate");
50674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
51674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        private Class iface;
52674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        private Class targetClass;
53674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
54674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        public Generator() {
55674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            super(SOURCE);
56674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
57674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
58674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        public void setInterface(Class iface) {
59674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            this.iface = iface;
60674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
61674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
62674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        public void setTargetClass(Class targetClass) {
63674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            this.targetClass = targetClass;
64674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
65674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
66674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        public ConstructorDelegate create() {
67674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            setNamePrefix(targetClass.getName());
68674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            Object key = KEY_FACTORY.newInstance(iface.getName(), targetClass.getName());
69674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            return (ConstructorDelegate)super.create(key);
70674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
71674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
72674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        protected ClassLoader getDefaultClassLoader() {
73674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            return targetClass.getClassLoader();
74674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
75674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
76674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        public void generateClass(ClassVisitor v) {
77674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            setNamePrefix(targetClass.getName());
78674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
79674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            final Method newInstance = ReflectUtils.findNewInstance(iface);
80674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            if (!newInstance.getReturnType().isAssignableFrom(targetClass)) {
81674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                throw new IllegalArgumentException("incompatible return type");
82674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
83674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            final Constructor constructor;
84674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            try {
85674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                constructor = targetClass.getDeclaredConstructor(newInstance.getParameterTypes());
86674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            } catch (NoSuchMethodException e) {
87674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                throw new IllegalArgumentException("interface does not match any known constructor");
88674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
89674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
90674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            ClassEmitter ce = new ClassEmitter(v);
91674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            ce.begin_class(Constants.V1_2,
92674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                           Constants.ACC_PUBLIC,
93674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                           getClassName(),
94674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                           CONSTRUCTOR_DELEGATE,
95674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                           new Type[]{ Type.getType(iface) },
96674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                           Constants.SOURCE_FILE);
97674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            Type declaring = Type.getType(constructor.getDeclaringClass());
98674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            EmitUtils.null_constructor(ce);
99674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC,
100674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                            ReflectUtils.getSignature(newInstance),
101674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                            ReflectUtils.getExceptionTypes(newInstance));
102674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.new_instance(declaring);
103674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.dup();
104674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.load_args();
105674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.invoke_constructor(declaring, ReflectUtils.getSignature(constructor));
106674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.return_value();
107674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.end_method();
108674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            ce.end_class();
109674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
110674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
111674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        protected Object firstInstance(Class type) {
112674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            return ReflectUtils.newInstance(type);
113674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
114674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
115674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        protected Object nextInstance(Object instance) {
116674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            return instance;
117674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
118674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
119674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen}
120