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