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.transform.impl; 17 18import java.lang.reflect.*; 19import java.util.*; 20 21import org.mockito.asm.Attribute; 22import org.mockito.asm.Type; 23import org.mockito.cglib.core.*; 24import org.mockito.cglib.transform.*; 25 26/** 27 * @author Juozas Baliuka 28 */ 29public class AddDelegateTransformer extends ClassEmitterTransformer { 30 private static final String DELEGATE = "$CGLIB_DELEGATE"; 31 private static final Signature CSTRUCT_OBJECT = 32 TypeUtils.parseSignature("void <init>(Object)"); 33 34 private Class[] delegateIf; 35 private Class delegateImpl; 36 private Type delegateType; 37 38 /** Creates a new instance of AddDelegateTransformer */ 39 public AddDelegateTransformer(Class delegateIf[], Class delegateImpl) { 40 try { 41 delegateImpl.getConstructor(new Class[]{ Object.class }); 42 this.delegateIf = delegateIf; 43 this.delegateImpl = delegateImpl; 44 delegateType = Type.getType(delegateImpl); 45 } catch (NoSuchMethodException e) { 46 throw new CodeGenerationException(e); 47 } 48 } 49 50 public void begin_class(int version, int access, String className, Type superType, Type[] interfaces, String sourceFile) { 51 52 if(!TypeUtils.isInterface(access)){ 53 54 Type[] all = TypeUtils.add(interfaces, TypeUtils.getTypes(delegateIf)); 55 super.begin_class(version, access, className, superType, all, sourceFile); 56 57 declare_field(Constants.ACC_PRIVATE | Constants.ACC_TRANSIENT, 58 DELEGATE, 59 delegateType, 60 null); 61 for (int i = 0; i < delegateIf.length; i++) { 62 Method[] methods = delegateIf[i].getMethods(); 63 for (int j = 0; j < methods.length; j++) { 64 if (Modifier.isAbstract(methods[j].getModifiers())) { 65 addDelegate(methods[j]); 66 } 67 } 68 } 69 }else{ 70 super.begin_class(version, access, className, superType, interfaces, sourceFile); 71 } 72 } 73 74 public CodeEmitter begin_method(int access, Signature sig, Type[] exceptions) { 75 final CodeEmitter e = super.begin_method(access, sig, exceptions); 76 if (sig.getName().equals(Constants.CONSTRUCTOR_NAME)) { 77 return new CodeEmitter(e) { 78 private boolean transformInit = true; 79 public void visitMethodInsn(int opcode, String owner, String name, String desc) { 80 super.visitMethodInsn(opcode, owner, name, desc); 81 if (transformInit && opcode == Constants.INVOKESPECIAL) { 82 load_this(); 83 new_instance(delegateType); 84 dup(); 85 load_this(); 86 invoke_constructor(delegateType, CSTRUCT_OBJECT); 87 putfield(DELEGATE); 88 transformInit = false; 89 } 90 } 91 }; 92 } 93 return e; 94 } 95 96 private void addDelegate(Method m) { 97 Method delegate; 98 try { 99 delegate = delegateImpl.getMethod(m.getName(), m.getParameterTypes()); 100 if (!delegate.getReturnType().getName().equals(m.getReturnType().getName())){ 101 throw new IllegalArgumentException("Invalid delegate signature " + delegate); 102 } 103 } catch (NoSuchMethodException e) { 104 throw new CodeGenerationException(e); 105 } 106 107 final Signature sig = ReflectUtils.getSignature(m); 108 Type[] exceptions = TypeUtils.getTypes(m.getExceptionTypes()); 109 CodeEmitter e = super.begin_method(Constants.ACC_PUBLIC, sig, exceptions); 110 e.load_this(); 111 e.getfield(DELEGATE); 112 e.load_args(); 113 e.invoke_virtual(delegateType, sig); 114 e.return_value(); 115 e.end_method(); 116 } 117} 118 119 120 121