/*
 * Copyright 2003,2004 The Apache Software Foundation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.sf.cglib.proxy;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import net.sf.cglib.core.AbstractClassGenerator;
import net.sf.cglib.core.CodeGenerationException;
import net.sf.cglib.core.GeneratorStrategy;
import net.sf.cglib.core.NamingPolicy;
import net.sf.cglib.core.Signature;
import net.sf.cglib.reflect.FastClass;

Classes generated by Enhancer pass this object to the registered MethodInterceptor objects when an intercepted method is invoked. It can be used to either invoke the original method, or call the same method on a different object of the same type.
Version:$Id: MethodProxy.java,v 1.16 2009/01/11 20:09:48 herbyderby Exp $
/** * Classes generated by {@link Enhancer} pass this object to the * registered {@link MethodInterceptor} objects when an intercepted method is invoked. It can * be used to either invoke the original method, or call the same method on a different * object of the same type. * @version $Id: MethodProxy.java,v 1.16 2009/01/11 20:09:48 herbyderby Exp $ */
public class MethodProxy { private Signature sig1; private Signature sig2; private CreateInfo createInfo; private final Object initLock = new Object(); private volatile FastClassInfo fastClassInfo;
For internal use by Enhancer only; see the FastMethod class for similar functionality.
/** * For internal use by {@link Enhancer} only; see the {@link net.sf.cglib.reflect.FastMethod} class * for similar functionality. */
public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) { MethodProxy proxy = new MethodProxy(); proxy.sig1 = new Signature(name1, desc); proxy.sig2 = new Signature(name2, desc); proxy.createInfo = new CreateInfo(c1, c2); return proxy; } private void init() { /* * Using a volatile invariant allows us to initialize the FastClass and * method index pairs atomically. * * Double-checked locking is safe with volatile in Java 5. Before 1.5 this * code could allow fastClassInfo to be instantiated more than once, which * appears to be benign. */ if (fastClassInfo == null) { synchronized (initLock) { if (fastClassInfo == null) { CreateInfo ci = createInfo; FastClassInfo fci = new FastClassInfo(); fci.f1 = helper(ci, ci.c1); fci.f2 = helper(ci, ci.c2); fci.i1 = fci.f1.getIndex(sig1); fci.i2 = fci.f2.getIndex(sig2); fastClassInfo = fci; createInfo = null; } } } } private static class FastClassInfo { FastClass f1; FastClass f2; int i1; int i2; } private static class CreateInfo { Class c1; Class c2; NamingPolicy namingPolicy; GeneratorStrategy strategy; boolean attemptLoad; public CreateInfo(Class c1, Class c2) { this.c1 = c1; this.c2 = c2; AbstractClassGenerator fromEnhancer = AbstractClassGenerator.getCurrent(); if (fromEnhancer != null) { namingPolicy = fromEnhancer.getNamingPolicy(); strategy = fromEnhancer.getStrategy(); attemptLoad = fromEnhancer.getAttemptLoad(); } } } private static FastClass helper(CreateInfo ci, Class type) { FastClass.Generator g = new FastClass.Generator(); g.setType(type); g.setClassLoader(ci.c2.getClassLoader()); g.setNamingPolicy(ci.namingPolicy); g.setStrategy(ci.strategy); g.setAttemptLoad(ci.attemptLoad); return g.create(); } private MethodProxy() { }
Return the signature of the proxied method.
/** * Return the signature of the proxied method. */
public Signature getSignature() { return sig1; }
Return the name of the synthetic method created by CGLIB which is used by invokeSuper to invoke the superclass (non-intercepted) method implementation. The parameter types are the same as the proxied method.
/** * Return the name of the synthetic method created by CGLIB which is * used by {@link #invokeSuper} to invoke the superclass * (non-intercepted) method implementation. The parameter types are * the same as the proxied method. */
public String getSuperName() { return sig2.getName(); }
Return the FastClass method index for the method used by invokeSuper. This index uniquely identifies the method within the generated proxy, and therefore can be useful to reference external metadata.
See Also:
/** * Return the {@link net.sf.cglib.reflect.FastClass} method index * for the method used by {@link #invokeSuper}. This index uniquely * identifies the method within the generated proxy, and therefore * can be useful to reference external metadata. * @see #getSuperName */
public int getSuperIndex() { init(); return fastClassInfo.i2; } // For testing FastClass getFastClass() { init(); return fastClassInfo.f1; } // For testing FastClass getSuperFastClass() { init(); return fastClassInfo.f2; }
Return the MethodProxy used when intercepting the method matching the given signature.
Params:
  • type – the class generated by Enhancer
  • sig – the signature to match
Throws:
Returns:the MethodProxy instance, or null if no applicable matching method is found
/** * Return the <code>MethodProxy</code> used when intercepting the method * matching the given signature. * @param type the class generated by Enhancer * @param sig the signature to match * @return the MethodProxy instance, or null if no applicable matching method is found * @throws IllegalArgumentException if the Class was not created by Enhancer or does not use a MethodInterceptor */
public static MethodProxy find(Class type, Signature sig) { try { Method m = type.getDeclaredMethod(MethodInterceptorGenerator.FIND_PROXY_NAME, MethodInterceptorGenerator.FIND_PROXY_TYPES); return (MethodProxy)m.invoke(null, new Object[]{ sig }); } catch (NoSuchMethodException e) { throw new IllegalArgumentException("Class " + type + " does not use a MethodInterceptor"); } catch (IllegalAccessException e) { throw new CodeGenerationException(e); } catch (InvocationTargetException e) { throw new CodeGenerationException(e); } }
Invoke the original method, on a different object of the same type.
Params:
  • obj – the compatible object; recursion will result if you use the object passed as the first argument to the MethodInterceptor (usually not what you want)
  • args – the arguments passed to the intercepted method; you may substitute a different argument array as long as the types are compatible
Throws:
  • Throwable – the bare exceptions thrown by the called method are passed through without wrapping in an InvocationTargetException
See Also:
/** * Invoke the original method, on a different object of the same type. * @param obj the compatible object; recursion will result if you use the object passed as the first * argument to the MethodInterceptor (usually not what you want) * @param args the arguments passed to the intercepted method; you may substitute a different * argument array as long as the types are compatible * @see MethodInterceptor#intercept * @throws Throwable the bare exceptions thrown by the called method are passed through * without wrapping in an <code>InvocationTargetException</code> */
public Object invoke(Object obj, Object[] args) throws Throwable { try { init(); FastClassInfo fci = fastClassInfo; return fci.f1.invoke(fci.i1, obj, args); } catch (InvocationTargetException e) { throw e.getTargetException(); } catch (IllegalArgumentException e) { if (fastClassInfo.i1 < 0) throw new IllegalArgumentException("Protected method: " + sig1); throw e; } }
Invoke the original (super) method on the specified object.
Params:
  • obj – the enhanced object, must be the object passed as the first argument to the MethodInterceptor
  • args – the arguments passed to the intercepted method; you may substitute a different argument array as long as the types are compatible
Throws:
  • Throwable – the bare exceptions thrown by the called method are passed through without wrapping in an InvocationTargetException
See Also:
/** * Invoke the original (super) method on the specified object. * @param obj the enhanced object, must be the object passed as the first * argument to the MethodInterceptor * @param args the arguments passed to the intercepted method; you may substitute a different * argument array as long as the types are compatible * @see MethodInterceptor#intercept * @throws Throwable the bare exceptions thrown by the called method are passed through * without wrapping in an <code>InvocationTargetException</code> */
public Object invokeSuper(Object obj, Object[] args) throws Throwable { try { init(); FastClassInfo fci = fastClassInfo; return fci.f2.invoke(fci.i2, obj, args); } catch (InvocationTargetException e) { throw e.getTargetException(); } } }