Class Enhancer

All Implemented Interfaces:
ClassGenerator

public class Enhancer extends AbstractClassGenerator
Generates dynamic subclasses to enable method interception. This class started as a substitute for the standard Dynamic Proxy support included with JDK 1.3, but one that allowed the proxies to extend a concrete base class, in addition to implementing interfaces. The dynamically generated subclasses override the non-final methods of the superclass and have hooks which callback to user-defined interceptor implementations.

The original and most general callback type is the MethodInterceptor, which in AOP terms enables "around advice"--that is, you can invoke custom code both before and after the invocation of the "super" method. In addition you can modify the arguments before calling the super method, or not call it at all.

Although MethodInterceptor is generic enough to meet any interception need, it is often overkill. For simplicity and performance, additional specialized callback types, such as LazyLoader are also available. Often a single callback will be used per enhanced class, but you can control which callback is used on a per-method basis with a CallbackFilter.

The most common uses of this class are embodied in the static helper methods. For advanced needs, such as customizing the ClassLoader to use, you should create a new instance of Enhancer. Other classes within CGLIB follow a similar pattern.

All enhanced objects implement the Factory interface, unless setUseFactory(boolean) is used to explicitly disable this feature. The Factory interface provides an API to change the callbacks of an existing object, as well as a faster and easier way to create new instances of the same type.

For an almost drop-in replacement for java.lang.reflect.Proxy, see the Proxy class.

  • Field Details

    • ALL_ZERO

      private static final CallbackFilter ALL_ZERO
    • SOURCE

      private static final AbstractClassGenerator.Source SOURCE
    • KEY_FACTORY

      private static final Enhancer.EnhancerKey KEY_FACTORY
    • BOUND_FIELD

      private static final String BOUND_FIELD
      See Also:
    • FACTORY_DATA_FIELD

      private static final String FACTORY_DATA_FIELD
      See Also:
    • THREAD_CALLBACKS_FIELD

      private static final String THREAD_CALLBACKS_FIELD
      See Also:
    • STATIC_CALLBACKS_FIELD

      private static final String STATIC_CALLBACKS_FIELD
      See Also:
    • SET_THREAD_CALLBACKS_NAME

      private static final String SET_THREAD_CALLBACKS_NAME
      See Also:
    • SET_STATIC_CALLBACKS_NAME

      private static final String SET_STATIC_CALLBACKS_NAME
      See Also:
    • CONSTRUCTED_FIELD

      private static final String CONSTRUCTED_FIELD
      See Also:
    • CALLBACK_FILTER_FIELD

      private static final String CALLBACK_FILTER_FIELD
      AbstractClassGenerator.ClassLoaderData.generatedClasses requires to keep cache key in a good shape (the keys should be up and running if the proxy class is alive), and one of the cache keys is CallbackFilter. That is why the generated class contains static field that keeps strong reference to the filter.

      This dance achieves two goals: ensures generated class is reusable and available through generatedClasses cache, and it enables to unload classloader and the related CallbackFilter in case user does not need that

      See Also:
    • OBJECT_TYPE

      private static final org.objectweb.asm.Type OBJECT_TYPE
    • FACTORY

      private static final org.objectweb.asm.Type FACTORY
    • ILLEGAL_STATE_EXCEPTION

      private static final org.objectweb.asm.Type ILLEGAL_STATE_EXCEPTION
    • ILLEGAL_ARGUMENT_EXCEPTION

      private static final org.objectweb.asm.Type ILLEGAL_ARGUMENT_EXCEPTION
    • THREAD_LOCAL

      private static final org.objectweb.asm.Type THREAD_LOCAL
    • CALLBACK

      private static final org.objectweb.asm.Type CALLBACK
    • CALLBACK_ARRAY

      private static final org.objectweb.asm.Type CALLBACK_ARRAY
    • CSTRUCT_NULL

      private static final Signature CSTRUCT_NULL
    • SET_THREAD_CALLBACKS

      private static final Signature SET_THREAD_CALLBACKS
    • SET_STATIC_CALLBACKS

      private static final Signature SET_STATIC_CALLBACKS
    • NEW_INSTANCE

      private static final Signature NEW_INSTANCE
    • MULTIARG_NEW_INSTANCE

      private static final Signature MULTIARG_NEW_INSTANCE
    • SINGLE_NEW_INSTANCE

      private static final Signature SINGLE_NEW_INSTANCE
    • SET_CALLBACK

      private static final Signature SET_CALLBACK
    • GET_CALLBACK

      private static final Signature GET_CALLBACK
    • SET_CALLBACKS

      private static final Signature SET_CALLBACKS
    • GET_CALLBACKS

      private static final Signature GET_CALLBACKS
    • THREAD_LOCAL_GET

      private static final Signature THREAD_LOCAL_GET
    • THREAD_LOCAL_SET

      private static final Signature THREAD_LOCAL_SET
    • BIND_CALLBACKS

      private static final Signature BIND_CALLBACKS
    • currentData

      private Enhancer.EnhancerFactoryData currentData
    • currentKey

      private Object currentKey
    • interfaces

      private Class[] interfaces
    • filter

      private CallbackFilter filter
    • callbacks

      private Callback[] callbacks
    • callbackTypes

      private org.objectweb.asm.Type[] callbackTypes
    • validateCallbackTypes

      private boolean validateCallbackTypes
    • classOnly

      private boolean classOnly
    • superclass

      private Class superclass
    • argumentTypes

      private Class[] argumentTypes
    • arguments

      private Object[] arguments
    • useFactory

      private boolean useFactory
    • serialVersionUID

      private Long serialVersionUID
    • interceptDuringConstruction

      private boolean interceptDuringConstruction
  • Constructor Details

    • Enhancer

      public Enhancer()
      Create a new Enhancer. A new Enhancer object should be used for each generated object, and should not be shared across threads. To create additional instances of a generated class, use the Factory interface.
      See Also:
  • Method Details

    • setSuperclass

      public void setSuperclass(Class superclass)
      Set the class which the generated class will extend. As a convenience, if the supplied superclass is actually an interface, setInterfaces will be called with the appropriate argument instead. A non-interface argument must not be declared as final, and must have an accessible constructor.
      Parameters:
      superclass - class to extend or interface to implement
      See Also:
    • setInterfaces

      public void setInterfaces(Class[] interfaces)
      Set the interfaces to implement. The Factory interface will always be implemented regardless of what is specified here.
      Parameters:
      interfaces - array of interfaces to implement, or null
      See Also:
    • setCallbackFilter

      public void setCallbackFilter(CallbackFilter filter)
      Set the CallbackFilter used to map the generated class' methods to a particular callback index. New object instances will always use the same mapping, but may use different actual callback objects.
      Parameters:
      filter - the callback filter to use when generating a new class
      See Also:
    • setCallback

      public void setCallback(Callback callback)
      Set the single Callback to use. Ignored if you use createClass().
      Parameters:
      callback - the callback to use for all methods
      See Also:
    • setCallbacks

      public void setCallbacks(Callback[] callbacks)
      Set the array of callbacks to use. Ignored if you use createClass(). You must use a CallbackFilter to specify the index into this array for each method in the proxied class.
      Parameters:
      callbacks - the callback array
      See Also:
    • setUseFactory

      public void setUseFactory(boolean useFactory)
      Set whether the enhanced object instances should implement the Factory interface. This was added for tools that need for proxies to be more indistinguishable from their targets. Also, in some cases it may be necessary to disable the Factory interface to prevent code from changing the underlying callbacks.
      Parameters:
      useFactory - whether to implement Factory; default is true
    • setInterceptDuringConstruction

      public void setInterceptDuringConstruction(boolean interceptDuringConstruction)
      Set whether methods called from within the proxy's constructer will be intercepted. The default value is true. Unintercepted methods will call the method of the proxy's base class, if it exists.
      Parameters:
      interceptDuringConstruction - whether to intercept methods called from the constructor
    • setCallbackType

      public void setCallbackType(Class callbackType)
      Set the single type of Callback to use. This may be used instead of setCallback(net.sf.cglib.proxy.Callback) when calling createClass(), since it may not be possible to have an array of actual callback instances.
      Parameters:
      callbackType - the type of callback to use for all methods
      See Also:
    • setCallbackTypes

      public void setCallbackTypes(Class[] callbackTypes)
      Set the array of callback types to use. This may be used instead of setCallbacks(net.sf.cglib.proxy.Callback[]) when calling createClass(), since it may not be possible to have an array of actual callback instances. You must use a CallbackFilter to specify the index into this array for each method in the proxied class.
      Parameters:
      callbackTypes - the array of callback types
    • create

      public Object create()
      Generate a new class if necessary and uses the specified callbacks (if any) to create a new object instance. Uses the no-arg constructor of the superclass.
      Returns:
      a new instance
    • create

      public Object create(Class[] argumentTypes, Object[] arguments)
      Generate a new class if necessary and uses the specified callbacks (if any) to create a new object instance. Uses the constructor of the superclass matching the argumentTypes parameter, with the given arguments.
      Parameters:
      argumentTypes - constructor signature
      arguments - compatible wrapped arguments to pass to constructor
      Returns:
      a new instance
    • createClass

      public Class createClass()
      Generate a new class if necessary and return it without creating a new instance. This ignores any callbacks that have been set. To create a new instance you will have to use reflection, and methods called during the constructor will not be intercepted. To avoid this problem, use the multi-arg create method.
      See Also:
    • setSerialVersionUID

      public void setSerialVersionUID(Long sUID)
      Insert a static serialVersionUID field into the generated class.
      Parameters:
      sUID - the field value, or null to avoid generating field.
    • preValidate

      private void preValidate()
    • validate

      private void validate()
    • createHelper

      private Object createHelper()
    • generate

      protected Class generate(AbstractClassGenerator.ClassLoaderData data)
      Overrides:
      generate in class AbstractClassGenerator
    • getDefaultClassLoader

      protected ClassLoader getDefaultClassLoader()
      Specified by:
      getDefaultClassLoader in class AbstractClassGenerator
    • getProtectionDomain

      protected ProtectionDomain getProtectionDomain()
      Description copied from class: AbstractClassGenerator
      Returns the protection domain to use when defining the class.

      Default implementation returns null for using a default protection domain. Sub-classes may override to use a more specific protection domain.

      Overrides:
      getProtectionDomain in class AbstractClassGenerator
      Returns:
      the protection domain (null for using a default)
    • rename

      private Signature rename(Signature sig, int index)
    • getMethods

      public static void getMethods(Class superclass, Class[] interfaces, List methods)
      Finds all of the methods that will be extended by an Enhancer-generated class using the specified superclass and interfaces. This can be useful in building a list of Callback objects. The methods are added to the end of the given list. Due to the subclassing nature of the classes generated by Enhancer, the methods are guaranteed to be non-static, non-final, and non-private. Each method signature will only occur once, even if it occurs in multiple classes.
      Parameters:
      superclass - the class that will be extended, or null
      interfaces - the list of interfaces that will be implemented, or null
      methods - the list into which to copy the applicable methods
    • getMethods

      private static void getMethods(Class superclass, Class[] interfaces, List methods, List interfaceMethods, Set forcePublic)
    • generateClass

      public void generateClass(org.objectweb.asm.ClassVisitor v) throws Exception
      Throws:
      Exception
    • filterConstructors

      protected void filterConstructors(Class sc, List constructors)
      Filter the list of constructors from the superclass. The constructors which remain will be included in the generated class. The default implementation is to filter out all private constructors, but subclasses may extend Enhancer to override this behavior.
      Parameters:
      sc - the superclass
      constructors - the list of all declared constructors from the superclass
      Throws:
      IllegalArgumentException - if there are no non-private constructors
    • firstInstance

      protected Object firstInstance(Class type) throws Exception
      This method should not be called in regular flow. Technically speaking wrapCachedClass(Class) uses Enhancer.EnhancerFactoryData as a cache value, and the latter enables faster instantiation than plain old reflection lookup and invoke. This method is left intact for backward compatibility reasons: just in case it was ever used.
      Specified by:
      firstInstance in class AbstractClassGenerator
      Parameters:
      type - class to instantiate
      Returns:
      newly created proxy instance
      Throws:
      Exception - if something goes wrong
    • nextInstance

      protected Object nextInstance(Object instance)
      Specified by:
      nextInstance in class AbstractClassGenerator
    • wrapCachedClass

      protected Object wrapCachedClass(Class klass)
      Overrides:
      wrapCachedClass in class AbstractClassGenerator
    • unwrapCachedValue

      protected Object unwrapCachedValue(Object cached)
      Overrides:
      unwrapCachedValue in class AbstractClassGenerator
    • registerCallbacks

      public static void registerCallbacks(Class generatedClass, Callback[] callbacks)
      Call this method to register the Callback array to use before creating a new instance of the generated class via reflection. If you are using an instance of Enhancer or the Factory interface to create new instances, this method is unnecessary. Its primary use is for when you want to cache and reuse a generated class yourself, and the generated class does not implement the Factory interface.

      Note that this method only registers the callbacks on the current thread. If you want to register callbacks for instances created by multiple threads, use registerStaticCallbacks(java.lang.Class, net.sf.cglib.proxy.Callback[]).

      The registered callbacks are overwritten and subsequently cleared when calling any of the create methods (such as create()), or any Factory newInstance method. Otherwise they are not cleared, and you should be careful to set them back to null after creating new instances via reflection if memory leakage is a concern.

      Parameters:
      generatedClass - a class previously created by Enhancer
      callbacks - the array of callbacks to use when instances of the generated class are created
      See Also:
    • registerStaticCallbacks

      public static void registerStaticCallbacks(Class generatedClass, Callback[] callbacks)
      Similar to registerCallbacks(java.lang.Class, net.sf.cglib.proxy.Callback[]), but suitable for use when multiple threads will be creating instances of the generated class. The thread-level callbacks will always override the static callbacks. Static callbacks are never cleared.
      Parameters:
      generatedClass - a class previously created by Enhancer
      callbacks - the array of callbacks to use when instances of the generated class are created
    • isEnhanced

      public static boolean isEnhanced(Class type)
      Determine if a class was generated using Enhancer.
      Parameters:
      type - any class
      Returns:
      whether the class was generated using Enhancer
    • setThreadCallbacks

      private static void setThreadCallbacks(Class type, Callback[] callbacks)
    • setCallbacksHelper

      private static void setCallbacksHelper(Class type, Callback[] callbacks, String methodName)
    • getCallbacksSetter

      private static Method getCallbacksSetter(Class type, String methodName) throws NoSuchMethodException
      Throws:
      NoSuchMethodException
    • createUsingReflection

      private Object createUsingReflection(Class type)
      Instantiates a proxy instance and assigns callback values. Implementation detail: java.lang.reflect instances are not cached, so this method should not be used on a hot path. This method is used when AbstractClassGenerator.setUseCache(boolean) is set to false.
      Parameters:
      type - class to instantiate
      Returns:
      newly created instance
    • create

      public static Object create(Class type, Callback callback)
      Helper method to create an intercepted object. For finer control over the generated instance, use a new instance of Enhancer instead of this static method.
      Parameters:
      type - class to extend or interface to implement
      callback - the callback to use for all methods
    • create

      public static Object create(Class superclass, Class[] interfaces, Callback callback)
      Helper method to create an intercepted object. For finer control over the generated instance, use a new instance of Enhancer instead of this static method.
      Parameters:
      superclass - class to extend or interface to implement
      interfaces - array of interfaces to implement, or null
      callback - the callback to use for all methods
    • create

      public static Object create(Class superclass, Class[] interfaces, CallbackFilter filter, Callback[] callbacks)
      Helper method to create an intercepted object. For finer control over the generated instance, use a new instance of Enhancer instead of this static method.
      Parameters:
      superclass - class to extend or interface to implement
      interfaces - array of interfaces to implement, or null
      filter - the callback filter to use when generating a new class
      callbacks - callback implementations to use for the enhanced object
    • emitDefaultConstructor

      private void emitDefaultConstructor(ClassEmitter ce)
    • emitConstructors

      private void emitConstructors(ClassEmitter ce, List constructors)
    • getCallbackKeys

      private int[] getCallbackKeys()
    • emitGetCallback

      private void emitGetCallback(ClassEmitter ce, int[] keys)
    • emitSetCallback

      private void emitSetCallback(ClassEmitter ce, int[] keys)
    • emitSetCallbacks

      private void emitSetCallbacks(ClassEmitter ce)
    • emitGetCallbacks

      private void emitGetCallbacks(ClassEmitter ce)
    • emitNewInstanceCallbacks

      private void emitNewInstanceCallbacks(ClassEmitter ce)
    • getThisType

      private org.objectweb.asm.Type getThisType(CodeEmitter e)
    • emitCommonNewInstance

      private void emitCommonNewInstance(CodeEmitter e)
    • emitNewInstanceCallback

      private void emitNewInstanceCallback(ClassEmitter ce)
    • emitNewInstanceMultiarg

      private void emitNewInstanceMultiarg(ClassEmitter ce, List constructors)
    • emitMethods

      private void emitMethods(ClassEmitter ce, List methods, List actualMethods)
    • emitSetThreadCallbacks

      private void emitSetThreadCallbacks(ClassEmitter ce)
    • emitSetStaticCallbacks

      private void emitSetStaticCallbacks(ClassEmitter ce)
    • emitCurrentCallback

      private void emitCurrentCallback(CodeEmitter e, int index)
    • emitBindCallbacks

      private void emitBindCallbacks(ClassEmitter ce)
    • getCallbackField

      private static String getCallbackField(int index)