2
* Copyright 2003,2004 The Apache Software Foundation
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
8
* http://www.apache.org/licenses/LICENSE-2.0
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.
16
package net.sf.cglib.proxy;
18
import java.lang.reflect.InvocationTargetException;
19
import java.lang.reflect.Method;
21
import net.sf.cglib.core.AbstractClassGenerator;
22
import net.sf.cglib.core.CodeGenerationException;
23
import net.sf.cglib.core.GeneratorStrategy;
24
import net.sf.cglib.core.NamingPolicy;
25
import net.sf.cglib.core.Signature;
26
import net.sf.cglib.reflect.FastClass;
29
* Classes generated by {@link Enhancer} pass this object to the
30
* registered {@link MethodInterceptor} objects when an intercepted method is invoked. It can
31
* be used to either invoke the original method, or call the same method on a different
32
* object of the same type.
33
* @version $Id: MethodProxy.java,v 1.14 2008/05/26 04:05:50 herbyderby Exp $
35
public class MethodProxy {
36
private Signature sig1;
37
private Signature sig2;
38
private CreateInfo createInfo;
40
private final Object initLock = new Object();
41
private volatile FastClassInfo fastClassInfo;
44
* For internal use by {@link Enhancer} only; see the {@link net.sf.cglib.reflect.FastMethod} class
45
* for similar functionality.
47
public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) {
48
MethodProxy proxy = new MethodProxy();
49
proxy.sig1 = new Signature(name1, desc);
50
proxy.sig2 = new Signature(name2, desc);
51
proxy.createInfo = new CreateInfo(c1, c2);
58
* Using a volatile invariant allows us to initialize the FastClass and
59
* method index pairs atomically.
61
* Double-checked locking is safe with volatile in Java 5. Before 1.5 this
62
* code could allow fastClassInfo to be instantiated more than once, which
63
* appears to be benign.
65
if (fastClassInfo == null)
67
synchronized (initLock)
69
if (fastClassInfo == null)
71
CreateInfo ci = createInfo;
73
FastClassInfo fci = new FastClassInfo();
74
fci.f1 = helper(ci, ci.c1);
75
fci.f2 = helper(ci, ci.c2);
76
fci.i1 = fci.f1.getIndex(sig1);
77
fci.i2 = fci.f2.getIndex(sig2);
84
private static class FastClassInfo
92
private static class CreateInfo
96
NamingPolicy namingPolicy;
97
GeneratorStrategy strategy;
100
public CreateInfo(Class c1, Class c2)
104
AbstractClassGenerator fromEnhancer = AbstractClassGenerator.getCurrent();
105
if (fromEnhancer != null) {
106
namingPolicy = fromEnhancer.getNamingPolicy();
107
strategy = fromEnhancer.getStrategy();
108
attemptLoad = fromEnhancer.getAttemptLoad();
113
private static FastClass helper(CreateInfo ci, Class type) {
114
FastClass.Generator g = new FastClass.Generator();
116
g.setClassLoader(ci.c2.getClassLoader());
117
g.setNamingPolicy(ci.namingPolicy);
118
g.setStrategy(ci.strategy);
119
g.setAttemptLoad(ci.attemptLoad);
123
private MethodProxy() {
127
* Return the signature of the proxied method.
129
public Signature getSignature() {
134
* Return the name of the synthetic method created by CGLIB which is
135
* used by {@link #invokeSuper} to invoke the superclass
136
* (non-intercepted) method implementation. The parameter types are
137
* the same as the proxied method.
139
public String getSuperName() {
140
return sig2.getName();
144
* Return the {@link net.sf.cglib.reflect.FastClass} method index
145
* for the method used by {@link #invokeSuper}. This index uniquely
146
* identifies the method within the generated proxy, and therefore
147
* can be useful to reference external metadata.
150
public int getSuperIndex() {
152
return fastClassInfo.i2;
156
* Return the <code>MethodProxy</code> used when intercepting the method
157
* matching the given signature.
158
* @param type the class generated by Enhancer
159
* @param sig the signature to match
160
* @return the MethodProxy instance, or null if no applicable matching method is found
161
* @throws IllegalArgumentException if the Class was not created by Enhancer or does not use a MethodInterceptor
163
public static MethodProxy find(Class type, Signature sig) {
165
Method m = type.getDeclaredMethod(MethodInterceptorGenerator.FIND_PROXY_NAME,
166
MethodInterceptorGenerator.FIND_PROXY_TYPES);
167
return (MethodProxy)m.invoke(null, new Object[]{ sig });
168
} catch (NoSuchMethodException e) {
169
throw new IllegalArgumentException("Class " + type + " does not use a MethodInterceptor");
170
} catch (IllegalAccessException e) {
171
throw new CodeGenerationException(e);
172
} catch (InvocationTargetException e) {
173
throw new CodeGenerationException(e);
178
* Invoke the original method, on a different object of the same type.
179
* @param obj the compatible object; recursion will result if you use the object passed as the first
180
* argument to the MethodInterceptor (usually not what you want)
181
* @param args the arguments passed to the intercepted method; you may substitute a different
182
* argument array as long as the types are compatible
183
* @see MethodInterceptor#intercept
184
* @throws Throwable the bare exceptions thrown by the called method are passed through
185
* without wrapping in an <code>InvocationTargetException</code>
187
public Object invoke(Object obj, Object[] args) throws Throwable {
190
FastClassInfo fci = fastClassInfo;
191
return fci.f1.invoke(fci.i1, obj, args);
192
} catch (InvocationTargetException e) {
193
throw e.getTargetException();
194
} catch (IllegalArgumentException e) {
195
if (fastClassInfo.i1 < 0)
196
throw new IllegalArgumentException("Protected method: " + sig1);
202
* Invoke the original (super) method on the specified object.
203
* @param obj the enhanced object, must be the object passed as the first
204
* argument to the MethodInterceptor
205
* @param args the arguments passed to the intercepted method; you may substitute a different
206
* argument array as long as the types are compatible
207
* @see MethodInterceptor#intercept
208
* @throws Throwable the bare exceptions thrown by the called method are passed through
209
* without wrapping in an <code>InvocationTargetException</code>
211
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
214
FastClassInfo fci = fastClassInfo;
215
return fci.f2.invoke(fci.i2, obj, args);
216
} catch (InvocationTargetException e) {
217
throw e.getTargetException();