MixinEmitter.java revision 674060f01e9090cd21b3c5656cc3204912ad17a6
1/*
2 * Copyright 2003,2004 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.proxy;
17
18import java.lang.reflect.Method;
19import java.util.*;
20
21import org.mockito.asm.ClassVisitor;
22import org.mockito.asm.Type;
23import org.mockito.cglib.core.*;
24
25/**
26 * @author Chris Nokleberg
27 * @version $Id: MixinEmitter.java,v 1.9 2006/08/27 21:04:37 herbyderby Exp $
28 */
29class MixinEmitter extends ClassEmitter {
30    private static final String FIELD_NAME = "CGLIB$DELEGATES";
31    private static final Signature CSTRUCT_OBJECT_ARRAY =
32      TypeUtils.parseConstructor("Object[]");
33    private static final Type MIXIN =
34      TypeUtils.parseType("org.mockito.cglib.proxy.Mixin");
35    private static final Signature NEW_INSTANCE =
36      new Signature("newInstance", MIXIN, new Type[]{ Constants.TYPE_OBJECT_ARRAY });
37
38    public MixinEmitter(ClassVisitor v, String className, Class[] classes, int[] route) {
39        super(v);
40
41        begin_class(Constants.V1_2,
42                    Constants.ACC_PUBLIC,
43                    className,
44                    MIXIN,
45                    TypeUtils.getTypes(getInterfaces(classes)),
46                    Constants.SOURCE_FILE);
47        EmitUtils.null_constructor(this);
48        EmitUtils.factory_method(this, NEW_INSTANCE);
49
50        declare_field(Constants.ACC_PRIVATE, FIELD_NAME, Constants.TYPE_OBJECT_ARRAY, null);
51
52        CodeEmitter e = begin_method(Constants.ACC_PUBLIC, CSTRUCT_OBJECT_ARRAY, null);
53        e.load_this();
54        e.super_invoke_constructor();
55        e.load_this();
56        e.load_arg(0);
57        e.putfield(FIELD_NAME);
58        e.return_value();
59        e.end_method();
60
61        Set unique = new HashSet();
62        for (int i = 0; i < classes.length; i++) {
63            Method[] methods = getMethods(classes[i]);
64            for (int j = 0; j < methods.length; j++) {
65                if (unique.add(MethodWrapper.create(methods[j]))) {
66                    MethodInfo method = ReflectUtils.getMethodInfo(methods[j]);
67                    e = EmitUtils.begin_method(this, method, Constants.ACC_PUBLIC);
68                    e.load_this();
69                    e.getfield(FIELD_NAME);
70                    e.aaload((route != null) ? route[i] : i);
71                    e.checkcast(method.getClassInfo().getType());
72                    e.load_args();
73                    e.invoke(method);
74                    e.return_value();
75                    e.end_method();
76                }
77            }
78        }
79
80        end_class();
81    }
82
83    protected Class[] getInterfaces(Class[] classes) {
84        return classes;
85    }
86
87    protected Method[] getMethods(Class type) {
88        return type.getMethods();
89    }
90}
91