public class Enhancer extends AbstractClassGenerator
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.
Modifier and Type | Class and Description |
---|---|
(package private) static class |
Enhancer.EnhancerFactoryData
The idea of the class is to cache relevant java.lang.reflect instances so
proxy-class can be instantiated faster that when using
ReflectUtils.newInstance(Class, Class[], Object[])
and setThreadCallbacks(Class, Callback[]) |
static interface |
Enhancer.EnhancerKey
Internal interface, only public due to ClassLoader issues.
|
AbstractClassGenerator.ClassLoaderData, AbstractClassGenerator.Source
Modifier and Type | Field and Description |
---|---|
private static CallbackFilter |
ALL_ZERO |
private java.lang.Object[] |
arguments |
private java.lang.Class[] |
argumentTypes |
private static Signature |
BIND_CALLBACKS |
private static java.lang.String |
BOUND_FIELD |
private static Type |
CALLBACK |
private static Type |
CALLBACK_ARRAY |
private static java.lang.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 . |
private Callback[] |
callbacks |
private Type[] |
callbackTypes |
private boolean |
classOnly |
private static java.lang.String |
CONSTRUCTED_FIELD |
private static Signature |
CSTRUCT_NULL |
private Enhancer.EnhancerFactoryData |
currentData |
private java.lang.Object |
currentKey |
private static Type |
FACTORY |
private static java.lang.String |
FACTORY_DATA_FIELD |
private CallbackFilter |
filter |
private static Signature |
GET_CALLBACK |
private static Signature |
GET_CALLBACKS |
private static Type |
ILLEGAL_ARGUMENT_EXCEPTION |
private static Type |
ILLEGAL_STATE_EXCEPTION |
private boolean |
interceptDuringConstruction |
private java.lang.Class[] |
interfaces |
private static Enhancer.EnhancerKey |
KEY_FACTORY |
private static Signature |
MULTIARG_NEW_INSTANCE |
private static Signature |
NEW_INSTANCE |
private static Type |
OBJECT_TYPE |
private java.lang.Long |
serialVersionUID |
private static Signature |
SET_CALLBACK |
private static Signature |
SET_CALLBACKS |
private static Signature |
SET_STATIC_CALLBACKS |
private static java.lang.String |
SET_STATIC_CALLBACKS_NAME |
private static Signature |
SET_THREAD_CALLBACKS |
private static java.lang.String |
SET_THREAD_CALLBACKS_NAME |
private static Signature |
SINGLE_NEW_INSTANCE |
private static AbstractClassGenerator.Source |
SOURCE |
private static java.lang.String |
STATIC_CALLBACKS_FIELD |
private java.lang.Class |
superclass |
private static java.lang.String |
THREAD_CALLBACKS_FIELD |
private static Type |
THREAD_LOCAL |
private static Signature |
THREAD_LOCAL_GET |
private static Signature |
THREAD_LOCAL_SET |
private boolean |
useFactory |
private boolean |
validateCallbackTypes |
Constructor and Description |
---|
Enhancer()
Create a new
Enhancer . |
Modifier and Type | Method and Description |
---|---|
java.lang.Object |
create()
Generate a new class if necessary and uses the specified
callbacks (if any) to create a new object instance.
|
java.lang.Object |
create(java.lang.Class[] argumentTypes,
java.lang.Object[] arguments)
Generate a new class if necessary and uses the specified
callbacks (if any) to create a new object instance.
|
static java.lang.Object |
create(java.lang.Class type,
Callback callback)
Helper method to create an intercepted object.
|
static java.lang.Object |
create(java.lang.Class superclass,
java.lang.Class[] interfaces,
Callback callback)
Helper method to create an intercepted object.
|
static java.lang.Object |
create(java.lang.Class superclass,
java.lang.Class[] interfaces,
CallbackFilter filter,
Callback[] callbacks)
Helper method to create an intercepted object.
|
java.lang.Class |
createClass()
Generate a new class if necessary and return it without creating a new instance.
|
private java.lang.Object |
createHelper() |
private java.lang.Object |
createUsingReflection(java.lang.Class type)
Instantiates a proxy instance and assigns callback values.
|
private void |
emitBindCallbacks(ClassEmitter ce) |
private void |
emitCommonNewInstance(CodeEmitter e) |
private void |
emitConstructors(ClassEmitter ce,
java.util.List constructors) |
private void |
emitCurrentCallback(CodeEmitter e,
int index) |
private void |
emitDefaultConstructor(ClassEmitter ce) |
private void |
emitGetCallback(ClassEmitter ce,
int[] keys) |
private void |
emitGetCallbacks(ClassEmitter ce) |
private void |
emitMethods(ClassEmitter ce,
java.util.List methods,
java.util.List actualMethods) |
private void |
emitNewInstanceCallback(ClassEmitter ce) |
private void |
emitNewInstanceCallbacks(ClassEmitter ce) |
private void |
emitNewInstanceMultiarg(ClassEmitter ce,
java.util.List constructors) |
private void |
emitSetCallback(ClassEmitter ce,
int[] keys) |
private void |
emitSetCallbacks(ClassEmitter ce) |
private void |
emitSetStaticCallbacks(ClassEmitter ce) |
private void |
emitSetThreadCallbacks(ClassEmitter ce) |
protected void |
filterConstructors(java.lang.Class sc,
java.util.List constructors)
Filter the list of constructors from the superclass.
|
protected java.lang.Object |
firstInstance(java.lang.Class type)
This method should not be called in regular flow.
|
protected java.lang.Class |
generate(AbstractClassGenerator.ClassLoaderData data) |
void |
generateClass(ClassVisitor v) |
private static java.lang.String |
getCallbackField(int index) |
private int[] |
getCallbackKeys() |
private static java.lang.reflect.Method |
getCallbacksSetter(java.lang.Class type,
java.lang.String methodName) |
protected java.lang.ClassLoader |
getDefaultClassLoader() |
static void |
getMethods(java.lang.Class superclass,
java.lang.Class[] interfaces,
java.util.List methods)
Finds all of the methods that will be extended by an
Enhancer-generated class using the specified superclass and
interfaces.
|
private static void |
getMethods(java.lang.Class superclass,
java.lang.Class[] interfaces,
java.util.List methods,
java.util.List interfaceMethods,
java.util.Set forcePublic) |
protected java.security.ProtectionDomain |
getProtectionDomain()
Returns the protection domain to use when defining the class.
|
private Type |
getThisType(CodeEmitter e) |
static boolean |
isEnhanced(java.lang.Class type)
Determine if a class was generated using
Enhancer . |
protected java.lang.Object |
nextInstance(java.lang.Object instance) |
private void |
preValidate() |
static void |
registerCallbacks(java.lang.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. |
static void |
registerStaticCallbacks(java.lang.Class generatedClass,
Callback[] callbacks)
Similar to
registerCallbacks(java.lang.Class, Callback[]) , but suitable for use
when multiple threads will be creating instances of the generated class. |
private Signature |
rename(Signature sig,
int index) |
void |
setCallback(Callback callback)
Set the single
Callback to use. |
void |
setCallbackFilter(CallbackFilter filter)
Set the
CallbackFilter used to map the generated class' methods
to a particular callback index. |
void |
setCallbacks(Callback[] callbacks)
Set the array of callbacks to use.
|
private static void |
setCallbacksHelper(java.lang.Class type,
Callback[] callbacks,
java.lang.String methodName) |
void |
setCallbackType(java.lang.Class callbackType)
Set the single type of
Callback to use. |
void |
setCallbackTypes(java.lang.Class[] callbackTypes)
Set the array of callback types to use.
|
void |
setInterceptDuringConstruction(boolean interceptDuringConstruction)
Set whether methods called from within the proxy's constructer
will be intercepted.
|
void |
setInterfaces(java.lang.Class[] interfaces)
Set the interfaces to implement.
|
void |
setSerialVersionUID(java.lang.Long sUID)
Insert a static serialVersionUID field into the generated class.
|
void |
setSuperclass(java.lang.Class superclass)
Set the class which the generated class will extend.
|
private static void |
setThreadCallbacks(java.lang.Class type,
Callback[] callbacks) |
void |
setUseFactory(boolean useFactory)
Set whether the enhanced object instances should implement
the
Factory interface. |
protected java.lang.Object |
unwrapCachedValue(java.lang.Object cached) |
private void |
validate() |
protected java.lang.Object |
wrapCachedClass(java.lang.Class klass) |
create, getAttemptLoad, getClassLoader, getClassName, getCurrent, getNamingPolicy, getStrategy, getUseCache, setAttemptLoad, setClassLoader, setContextClass, setNamePrefix, setNamingPolicy, setStrategy, setUseCache
private static final CallbackFilter ALL_ZERO
private static final AbstractClassGenerator.Source SOURCE
private static final Enhancer.EnhancerKey KEY_FACTORY
private static final java.lang.String BOUND_FIELD
private static final java.lang.String FACTORY_DATA_FIELD
private static final java.lang.String THREAD_CALLBACKS_FIELD
private static final java.lang.String STATIC_CALLBACKS_FIELD
private static final java.lang.String SET_THREAD_CALLBACKS_NAME
private static final java.lang.String SET_STATIC_CALLBACKS_NAME
private static final java.lang.String CONSTRUCTED_FIELD
private static final java.lang.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
private static final Type OBJECT_TYPE
private static final Type FACTORY
private static final Type ILLEGAL_STATE_EXCEPTION
private static final Type ILLEGAL_ARGUMENT_EXCEPTION
private static final Type THREAD_LOCAL
private static final Type CALLBACK
private static final Type CALLBACK_ARRAY
private static final Signature CSTRUCT_NULL
private static final Signature SET_THREAD_CALLBACKS
private static final Signature SET_STATIC_CALLBACKS
private static final Signature NEW_INSTANCE
private static final Signature MULTIARG_NEW_INSTANCE
private static final Signature SINGLE_NEW_INSTANCE
private static final Signature SET_CALLBACK
private static final Signature GET_CALLBACK
private static final Signature SET_CALLBACKS
private static final Signature GET_CALLBACKS
private static final Signature THREAD_LOCAL_GET
private static final Signature THREAD_LOCAL_SET
private static final Signature BIND_CALLBACKS
private Enhancer.EnhancerFactoryData currentData
private java.lang.Object currentKey
private java.lang.Class[] interfaces
private CallbackFilter filter
private Callback[] callbacks
private Type[] callbackTypes
private boolean validateCallbackTypes
private boolean classOnly
private java.lang.Class superclass
private java.lang.Class[] argumentTypes
private java.lang.Object[] arguments
private boolean useFactory
private java.lang.Long serialVersionUID
private boolean interceptDuringConstruction
public Enhancer()
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.Factory
public void setSuperclass(java.lang.Class superclass)
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.superclass
- class to extend or interface to implementsetInterfaces(Class[])
public void setInterfaces(java.lang.Class[] interfaces)
Factory
interface will
always be implemented regardless of what is specified here.interfaces
- array of interfaces to implement, or nullFactory
public void setCallbackFilter(CallbackFilter filter)
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.filter
- the callback filter to use when generating a new classsetCallbacks(Callback[])
public void setCallback(Callback callback)
Callback
to use.
Ignored if you use createClass()
.callback
- the callback to use for all methodssetCallbacks(Callback[])
public void setCallbacks(Callback[] callbacks)
createClass()
.
You must use a CallbackFilter
to specify the index into this
array for each method in the proxied class.callbacks
- the callback arraysetCallbackFilter(CallbackFilter)
,
setCallback(Callback)
public void setUseFactory(boolean useFactory)
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.useFactory
- whether to implement Factory
; default is true
public void setInterceptDuringConstruction(boolean interceptDuringConstruction)
interceptDuringConstruction
- whether to intercept methods called from the constructorpublic void setCallbackType(java.lang.Class callbackType)
Callback
to use.
This may be used instead of setCallback(Callback)
when calling
createClass()
, since it may not be possible to have
an array of actual callback instances.callbackType
- the type of callback to use for all methodssetCallbackTypes(java.lang.Class[])
public void setCallbackTypes(java.lang.Class[] callbackTypes)
setCallbacks(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.callbackTypes
- the array of callback typespublic java.lang.Object create()
public java.lang.Object create(java.lang.Class[] argumentTypes, java.lang.Object[] arguments)
argumentTypes
parameter, with the given arguments.argumentTypes
- constructor signaturearguments
- compatible wrapped arguments to pass to constructorpublic java.lang.Class createClass()
create
method.create(Class[], Object[])
public void setSerialVersionUID(java.lang.Long sUID)
sUID
- the field value, or null to avoid generating field.private void preValidate()
private void validate()
private java.lang.Object createHelper()
protected java.lang.Class generate(AbstractClassGenerator.ClassLoaderData data)
generate
in class AbstractClassGenerator
protected java.lang.ClassLoader getDefaultClassLoader()
getDefaultClassLoader
in class AbstractClassGenerator
protected java.security.ProtectionDomain getProtectionDomain()
AbstractClassGenerator
Default implementation returns null
for using a default protection domain. Sub-classes may
override to use a more specific protection domain.
getProtectionDomain
in class AbstractClassGenerator
null
for using a default)private Signature rename(Signature sig, int index)
public static void getMethods(java.lang.Class superclass, java.lang.Class[] interfaces, java.util.List methods)
superclass
- the class that will be extended, or nullinterfaces
- the list of interfaces that will be implemented, or nullmethods
- the list into which to copy the applicable methodsprivate static void getMethods(java.lang.Class superclass, java.lang.Class[] interfaces, java.util.List methods, java.util.List interfaceMethods, java.util.Set forcePublic)
public void generateClass(ClassVisitor v) throws java.lang.Exception
java.lang.Exception
protected void filterConstructors(java.lang.Class sc, java.util.List constructors)
sc
- the superclassconstructors
- the list of all declared constructors from the superclassjava.lang.IllegalArgumentException
- if there are no non-private constructorsprotected java.lang.Object firstInstance(java.lang.Class type) throws java.lang.Exception
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.firstInstance
in class AbstractClassGenerator
type
- class to instantiatejava.lang.Exception
- if something goes wrongprotected java.lang.Object nextInstance(java.lang.Object instance)
nextInstance
in class AbstractClassGenerator
protected java.lang.Object wrapCachedClass(java.lang.Class klass)
wrapCachedClass
in class AbstractClassGenerator
protected java.lang.Object unwrapCachedValue(java.lang.Object cached)
unwrapCachedValue
in class AbstractClassGenerator
public static void registerCallbacks(java.lang.Class generatedClass, Callback[] callbacks)
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, 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.
generatedClass
- a class previously created by Enhancer
callbacks
- the array of callbacks to use when instances of the generated
class are createdsetUseFactory(boolean)
public static void registerStaticCallbacks(java.lang.Class generatedClass, Callback[] callbacks)
registerCallbacks(java.lang.Class, 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.generatedClass
- a class previously created by Enhancer
callbacks
- the array of callbacks to use when instances of the generated
class are createdpublic static boolean isEnhanced(java.lang.Class type)
Enhancer
.type
- any classEnhancer
private static void setThreadCallbacks(java.lang.Class type, Callback[] callbacks)
private static void setCallbacksHelper(java.lang.Class type, Callback[] callbacks, java.lang.String methodName)
private static java.lang.reflect.Method getCallbacksSetter(java.lang.Class type, java.lang.String methodName) throws java.lang.NoSuchMethodException
java.lang.NoSuchMethodException
private java.lang.Object createUsingReflection(java.lang.Class type)
AbstractClassGenerator.setUseCache(boolean)
is set to false
.type
- class to instantiatepublic static java.lang.Object create(java.lang.Class type, Callback callback)
Enhancer
instead of this static method.type
- class to extend or interface to implementcallback
- the callback to use for all methodspublic static java.lang.Object create(java.lang.Class superclass, java.lang.Class[] interfaces, Callback callback)
Enhancer
instead of this static method.superclass
- class to extend or interface to implementinterfaces
- array of interfaces to implement, or nullcallback
- the callback to use for all methodspublic static java.lang.Object create(java.lang.Class superclass, java.lang.Class[] interfaces, CallbackFilter filter, Callback[] callbacks)
Enhancer
instead of this static method.superclass
- class to extend or interface to implementinterfaces
- array of interfaces to implement, or nullfilter
- the callback filter to use when generating a new classcallbacks
- callback implementations to use for the enhanced objectprivate void emitDefaultConstructor(ClassEmitter ce)
private void emitConstructors(ClassEmitter ce, java.util.List constructors)
private int[] getCallbackKeys()
private void emitGetCallback(ClassEmitter ce, int[] keys)
private void emitSetCallback(ClassEmitter ce, int[] keys)
private void emitSetCallbacks(ClassEmitter ce)
private void emitGetCallbacks(ClassEmitter ce)
private void emitNewInstanceCallbacks(ClassEmitter ce)
private Type getThisType(CodeEmitter e)
private void emitCommonNewInstance(CodeEmitter e)
private void emitNewInstanceCallback(ClassEmitter ce)
private void emitNewInstanceMultiarg(ClassEmitter ce, java.util.List constructors)
private void emitMethods(ClassEmitter ce, java.util.List methods, java.util.List actualMethods)
private void emitSetThreadCallbacks(ClassEmitter ce)
private void emitSetStaticCallbacks(ClassEmitter ce)
private void emitCurrentCallback(CodeEmitter e, int index)
private void emitBindCallbacks(ClassEmitter ce)
private static java.lang.String getCallbackField(int index)