AddDelegateTransformer.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.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