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.transform.impl;
17674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
18674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.asm.Attribute;
19674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.asm.ClassVisitor;
20674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.asm.Label;
21674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.asm.MethodAdapter;
22674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.asm.MethodVisitor;
23674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.asm.Type;
24674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.cglib.core.*;
25674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.cglib.transform.*;
26674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
27674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen/**
28674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @author Juozas Baliuka, Chris Nokleberg
29674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen */
30674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenpublic class InterceptFieldTransformer extends ClassEmitterTransformer {
31674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final String CALLBACK_FIELD = "$CGLIB_READ_WRITE_CALLBACK";
32674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Type CALLBACK =
33674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      TypeUtils.parseType("org.mockito.cglib.transform.impl.InterceptFieldCallback");
34674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Type ENABLED =
35674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      TypeUtils.parseType("org.mockito.cglib.transform.impl.InterceptFieldEnabled");
36674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Signature ENABLED_SET =
37674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      new Signature("setInterceptFieldCallback", Type.VOID_TYPE, new Type[]{ CALLBACK });
38674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static final Signature ENABLED_GET =
39674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen      new Signature("getInterceptFieldCallback", CALLBACK, new Type[0]);
40674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
41674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private InterceptFieldFilter filter;
42674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
43674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public InterceptFieldTransformer(InterceptFieldFilter filter) {
44674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        this.filter = filter;
45674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
46674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
47674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public void begin_class(int version, int access, String className, Type superType, Type[] interfaces, String sourceFile) {
48674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (!TypeUtils.isInterface(access)) {
49674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            super.begin_class(version, access, className, superType, TypeUtils.add(interfaces, ENABLED), sourceFile);
50674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
51674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            super.declare_field(Constants.ACC_PRIVATE | Constants.ACC_TRANSIENT,
52674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                CALLBACK_FIELD,
53674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                CALLBACK,
54674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                null);
55674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
56674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            CodeEmitter e;
57674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e = super.begin_method(Constants.ACC_PUBLIC, ENABLED_GET, null);
58674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.load_this();
59674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.getfield(CALLBACK_FIELD);
60674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.return_value();
61674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.end_method();
62674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
63674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e = super.begin_method(Constants.ACC_PUBLIC, ENABLED_SET, null);
64674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.load_this();
65674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.load_arg(0);
66674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.putfield(CALLBACK_FIELD);
67674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.return_value();
68674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.end_method();
69674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        } else {
70674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            super.begin_class(version, access, className, superType, interfaces, sourceFile);
71674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
72674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
73674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
74674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public void declare_field(int access, String name, Type type, Object value) {
75674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        super.declare_field(access, name, type, value);
76674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (!TypeUtils.isStatic(access)) {
77674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            if (filter.acceptRead(getClassType(), name)) {
78674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                addReadMethod(name, type);
79674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
80674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            if (filter.acceptWrite(getClassType(), name)) {
81674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                addWriteMethod(name, type);
82674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
83674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
84674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
85674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
86674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private void addReadMethod(String name, Type type) {
87674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        CodeEmitter e = super.begin_method(Constants.ACC_PUBLIC,
88674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                           readMethodSig(name, type.getDescriptor()),
89674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                           null);
90674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_this();
91674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.getfield(name);
92674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_this();
93674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.invoke_interface(ENABLED,ENABLED_GET);
94674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Label intercept = e.make_label();
95674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.ifnonnull(intercept);
96674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.return_value();
97674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
98674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.mark(intercept);
99674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Local result = e.make_local(type);
100674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.store_local(result);
101674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_this();
102674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.invoke_interface(ENABLED,ENABLED_GET);
103674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_this();
104674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.push(name);
105674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_local(result);
106674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.invoke_interface(CALLBACK, readCallbackSig(type));
107674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (!TypeUtils.isPrimitive(type)) {
108674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.checkcast(type);
109674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
110674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.return_value();
111674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.end_method();
112674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
113674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
114674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private void addWriteMethod(String name, Type type) {
115674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        CodeEmitter e = super.begin_method(Constants.ACC_PUBLIC,
116674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                           writeMethodSig(name, type.getDescriptor()),
117674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                           null);
118674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_this();
119674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.dup();
120674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.invoke_interface(ENABLED,ENABLED_GET);
121674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Label skip = e.make_label();
122674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.ifnull(skip);
123674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
124674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_this();
125674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.invoke_interface(ENABLED,ENABLED_GET);
126674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_this();
127674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.push(name);
128674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_this();
129674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.getfield(name);
130674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_arg(0);
131674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.invoke_interface(CALLBACK, writeCallbackSig(type));
132674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        if (!TypeUtils.isPrimitive(type)) {
133674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            e.checkcast(type);
134674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
135674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Label go = e.make_label();
136674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.goTo(go);
137674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.mark(skip);
138674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.load_arg(0);
139674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.mark(go);
140674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.putfield(name);
141674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.return_value();
142674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        e.end_method();
143674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
144674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
145674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    public CodeEmitter begin_method(int access, Signature sig, Type[] exceptions) {
146674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        return new CodeEmitter(super.begin_method(access, sig, exceptions)) {
147674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            public void visitFieldInsn(int opcode, String owner, String name, String desc) {
148674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                Type towner = TypeUtils.fromInternalName(owner);
149674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                switch (opcode) {
150674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                case Constants.GETFIELD:
151674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    if (filter.acceptRead(towner, name)) {
152674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        helper(towner, readMethodSig(name, desc));
153674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        return;
154674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    }
155674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    break;
156674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                case Constants.PUTFIELD:
157674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    if (filter.acceptWrite(towner, name)) {
158674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        helper(towner, writeMethodSig(name, desc));
159674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                        return;
160674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    }
161674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                    break;
162674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                }
163674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                super.visitFieldInsn(opcode, owner, name, desc);
164674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
165674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
166674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            private void helper(Type owner, Signature sig) {
167674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                invoke_virtual(owner, sig);
168674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            }
169674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        };
170674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
171674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
172674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static Signature readMethodSig(String name, String desc) {
173674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        return new Signature("$cglib_read_" + name, "()" + desc);
174674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
175674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
176674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static Signature writeMethodSig(String name, String desc) {
177674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        return new Signature("$cglib_write_" + name, "(" + desc + ")V");
178674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
179674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
180674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static Signature readCallbackSig(Type type) {
181674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Type remap = remap(type);
182674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        return new Signature("read" + callbackName(remap),
183674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                             remap,
184674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                             new Type[]{ Constants.TYPE_OBJECT,
185674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                         Constants.TYPE_STRING,
186674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                         remap });
187674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
188674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
189674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static Signature writeCallbackSig(Type type) {
190674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        Type remap = remap(type);
191674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        return new Signature("write" + callbackName(remap),
192674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                             remap,
193674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                             new Type[]{ Constants.TYPE_OBJECT,
194674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                         Constants.TYPE_STRING,
195674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                         remap,
196674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen                                         remap });
197674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
198674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
199674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static Type remap(Type type) {
200674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        switch (type.getSort()) {
201674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        case Type.OBJECT:
202674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        case Type.ARRAY:
203674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            return Constants.TYPE_OBJECT;
204674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        default:
205674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            return type;
206674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        }
207674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
208674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen
209674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    private static String callbackName(Type type) {
210674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen        return (type == Constants.TYPE_OBJECT) ?
211674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            "Object" :
212674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen            TypeUtils.upperFirst(TypeUtils.getClassName(type));
213674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen    }
214674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen}
215