|
||||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Objectorg.jpu.patterns.proxy.JPUInvocationHandler
This class is designed to make writing InvocationHandler
's easier and less error-prone, as well as to facilitate
more efficient delegation and a more natural inheritance-based delegation model. Its features are summarized below:
invoke()
method (inherited from InvocationHandler
) are delegated to the protected
method doInvoke(Object, Method, Object[], Object[])
which each subclass can override. This method returns a boolean
indicating whether it was able to handle the request at its level. Each subclass implementation can call
super.doInvoke()
to delegate the invocation to the superclass,
and can take appropriate action based on the boolean
returned. The subclass may choose to perform some action
in addition to, or in place of, the one defined in the superclass.
getProxy()
. Internal caching ensures that self-delegation incurs minimal overhead, and is in fact
more efficient than the cascaded if/else
clauses that tend to clutter invoke()
methods. It also
results in more maintainable invocation handlers because much of the delegation work is handled automatically.
Automatic self-delegation is enabled for all matching methods by default but can be disabled for certain methods, or for all
methods, by overriding autoDelegateToSelf(Object,Method,Object[])
, which returns a boolean indicating whether automatic self-delegation should
be performed for a given invocation. If automatic self-delegation is disabled, you can still invoke the delegation logic
explicitly by calling delegate(Object,Object,Method,Object[],Object[])
. This method will return a boolean
indicating whether it found (and
called) a matching method.
UndeclaredThrowableException
's which result when
the invocation handler fails to catch and rethrow a checked exception of a type that is not listed in the invoked method's
throws
clause. This is a common source of bugs in invocation handlers, because the compiler cannot
perform the same exception-related checks on an invocation handler that it can on a statically implemented
method.
JPUInvocationHandler
will call throwUnlistedException(Object,Method,Object[],Throwable)
for any exception that would otherwise result in
an UndeclaredThrowableException
exception. This method's default implementation simply throws
NestableRuntimeException
passing the unlisted exception to its constructor, but the subclass can override as
needed.
ProxyBean
class extends JPUInvocationHandler
and adds support for automatic
implementation of simple getter and setter methods along with change tracking.
Nested Class Summary | |
protected static class |
JPUInvocationHandler.DelegationCacheValue
Defines entries in the self-delegation cache. |
protected static class |
JPUInvocationHandler.DelegationState
|
Constructor Summary | |
JPUInvocationHandler()
|
Method Summary | |
protected boolean |
autoDelegateToSelf(java.lang.Object proxy,
java.lang.reflect.Method interfaceMethod,
java.lang.Object[] args)
Returns whether self delegation is performed automatically for any matching method invocations. |
protected boolean |
delegate(java.lang.Object proxy,
java.lang.Object target,
java.lang.reflect.Method interfaceMethod,
java.lang.Object[] args,
java.lang.Object[] result)
Attempts to delegate the given method invocation to " target ". |
protected void |
doGetImplementedInterfaces(java.util.Collection dest)
Default implementation does nothing, but subclasses can override to add to dest
the Class instances of any interfaces the generated proxy should implement,
in addition to those explicitly passed via the first parameter to
newProxy(Class[], ClassLoader) . |
protected boolean |
doInvoke(java.lang.Object proxy,
java.lang.reflect.Method method,
java.lang.Object[] args,
java.lang.Object[] result)
Overrides the method of JPUInvocationHandler . |
static long |
getCacheHits()
Returns the number of cache hits registered for the self-delegation cache since resetCacheCounters() was last called. |
static long |
getCacheMisses()
Returns the number of cache misses registered for the self-delegation cache since resetCacheCounters() was last called. |
protected java.lang.reflect.Method |
getCurrentInterfaceMethod()
Returns the interface method through which the current invocation was called. |
protected java.lang.ClassLoader |
getDefaultClassLoader()
Returns the ClassLoader to pass to the first parameter of Proxy.newInstance()
if null is passed as the second parameter to newProxy(Class[], ClassLoader) . |
protected java.lang.reflect.Method |
getDelegationMethod(java.lang.reflect.Method interfaceMethod)
Alias for " getDelegationTargetMethod( interfaceMethod, getClass() ) ". |
protected JPUInvocationHandler.DelegationState |
getDelegationState()
Returns the state of the self-delegation action that is currently in progress, or null if no self-delegation is
in progress. |
protected java.lang.reflect.Method |
getDelegationTargetMethod(java.lang.reflect.Method interfaceMethod,
java.lang.Class targetClass)
Returns the method on the invocation handler to which invocations on the given interface method should be delegated, or null if no such method exists. |
java.lang.Class[] |
getInterfaces(java.lang.Class[] moreClasses)
Returns all interfaces that this invocation handler's proxy implements. |
protected java.lang.Object |
getProxy()
Returns the proxy for which this invocation handler is currently handling an invocation. |
void |
initializeProxy(java.lang.Object newProxy)
Default implementation does nothing, but subclasses can override to perform any sort of initialization on a newly-generated proxy instance. |
java.lang.Object |
invoke(java.lang.Object proxy,
java.lang.reflect.Method interfaceMethod,
java.lang.Object[] args)
Method required by the InvocationHandler interface. |
java.lang.Object |
newProxy()
Convenience alias for " newProxy(null) ". |
java.lang.Object |
newProxy(java.lang.Class[] moreClasses)
Convenience alias for " newProxy(moreClasses, null) ". |
java.lang.Object |
newProxy(java.lang.Class[] moreClasses,
java.lang.ClassLoader loader)
Uses Proxy.newProxyInstance() to generate a proxy instance backed by this
invocation handler. |
static void |
resetCacheCounters()
Resets the counters used to measure the hit and miss rate of the self-delegation cache. |
protected void |
rethrow(java.lang.Object proxy,
java.lang.reflect.Method interfaceMethod,
java.lang.Object[] args,
java.lang.Throwable t)
Rethrows exceptions thrown from doInvoke(Object,Method,Object[],Object[]) . |
protected void |
setDelegationState(JPUInvocationHandler.DelegationState delegationState)
Sets the current self-delegation state to the given value. |
protected void |
throwUnhandledException(java.lang.reflect.Method method)
Throws an unchecked exception indiciating that the given method was not handled by the invocation handler. |
protected void |
throwUnlistedException(java.lang.Object proxy,
java.lang.reflect.Method interfaceMethod,
java.lang.Object[] args,
java.lang.Throwable t)
This method is called when an exception is thrown from doInvoke(Object,Method,Object[],Object[]) that is an illegal checked exception
for the interface method that was invoked; that is, the exception is not assignment compatible with any exception
class listed in the interface method's throws clause. |
protected boolean |
wouldDelegationInfinitelyRecurse(JPUInvocationHandler.DelegationState state,
java.lang.Object target,
java.lang.reflect.Method interfaceMethod)
Internal method used to ensure that a delegation call would not result in infinite recursion. |
Methods inherited from class java.lang.Object |
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
Constructor Detail |
public JPUInvocationHandler()
Method Detail |
protected void throwUnhandledException(java.lang.reflect.Method method)
UnhandledMethodCallException
, but subclasses are free to override.
public java.lang.Object invoke(java.lang.Object proxy, java.lang.reflect.Method interfaceMethod, java.lang.Object[] args) throws java.lang.Throwable
InvocationHandler
interface. Calls doInvoke(Object,Method,Object[],Object[])
, catching any exceptions
thrown from it and rethrowing them using the rethrow(Object,Method,Object[],Throwable)
method (which subclasses can override). If doInvoke()
returns false
(meaning the invocation was not handled), throws an exception by calling throwUnhandledException(Method)
,
which subclasses can override.
invoke
in interface java.lang.reflect.InvocationHandler
java.lang.Throwable
protected void rethrow(java.lang.Object proxy, java.lang.reflect.Method interfaceMethod, java.lang.Object[] args, java.lang.Throwable t) throws java.lang.Throwable
doInvoke(Object,Method,Object[],Object[])
. If the given Throwable
is an
Error
or RuntimeException
, it is rethrown as is. Else if the exception is
of a type that is compatible with the interface method's throws
clause, it is rethrown as
is. Else throwUnhandledException(Method)
is called, which subclasses can override.
java.lang.Throwable
protected void throwUnlistedException(java.lang.Object proxy, java.lang.reflect.Method interfaceMethod, java.lang.Object[] args, java.lang.Throwable t) throws java.lang.Throwable
doInvoke(Object,Method,Object[],Object[])
that is an illegal checked exception
for the interface method that was invoked; that is, the exception is not assignment compatible with any exception
class listed in the interface method's throws
clause. This method must throw either an unchecked exception or a checked
exception appearing in the throws clause of the method.
The default implementation throws a NestableRuntimeException
wrapping the given Throwable
,
but subclasses are free to override.
java.lang.Throwable
protected boolean wouldDelegationInfinitelyRecurse(JPUInvocationHandler.DelegationState state, java.lang.Object target, java.lang.reflect.Method interfaceMethod)
protected boolean autoDelegateToSelf(java.lang.Object proxy, java.lang.reflect.Method interfaceMethod, java.lang.Object[] args)
true
, but subclasses are free to override.
protected java.lang.reflect.Method getDelegationTargetMethod(java.lang.reflect.Method interfaceMethod, java.lang.Class targetClass) throws java.lang.Throwable
null
if no such method exists. Uses caching to ensure
that this lookup incurs minimal overhead.
java.lang.Throwable
protected java.lang.reflect.Method getDelegationMethod(java.lang.reflect.Method interfaceMethod) throws java.lang.Throwable
getDelegationTargetMethod( interfaceMethod, getClass() )
".
java.lang.Throwable
public static long getCacheMisses()
resetCacheCounters()
was last called.
public static long getCacheHits()
resetCacheCounters()
was last called.
public static void resetCacheCounters()
protected boolean delegate(java.lang.Object proxy, java.lang.Object target, java.lang.reflect.Method interfaceMethod, java.lang.Object[] args, java.lang.Object[] result) throws java.lang.Throwable
target
". If no matching
method could be found (as determined by a call to getDelegationTargetMethod(Method,Class)
),
this method returns false
. Else it invokes the method, setting result[0]
to its return value, and returns true
. Any exception thrown by
the invoked method will be allowed to propagate up.
java.lang.Throwable
protected JPUInvocationHandler.DelegationState getDelegationState()
null
if no self-delegation is
in progress.
protected void setDelegationState(JPUInvocationHandler.DelegationState delegationState)
protected java.lang.Object getProxy()
null
.
protected java.lang.reflect.Method getCurrentInterfaceMethod()
null
.
public java.lang.Object newProxy()
newProxy(null)
".
public java.lang.Object newProxy(java.lang.Class[] moreClasses)
newProxy(moreClasses, null)
".
public java.lang.Class[] getInterfaces(java.lang.Class[] moreClasses)
doGetImplementedInterfaces(Collection)
, plus
those passed via the moreClasses
parameter.
public java.lang.Object newProxy(java.lang.Class[] moreClasses, java.lang.ClassLoader loader)
Proxy.newProxyInstance()
to generate a proxy instance backed by this
invocation handler. The generated proxy will implement all interfaces returned by
getInterfaces(Class[])
.
Once the proxy is generated, this method calls
initializeProxy(Object)
, which
subclasses can override.
moreClasses
- Interfaces to implement in addition to those returned by
doGetImplementedInterfaces(Collection)
.
Can be null
.loader
- The ClassLoader
to pass as the first parameter to
Proxy.newProxyInstance()
. If null
,
getDefaultClassLoader()
is
called and its return value is used as the ClassLoader
.
protected java.lang.ClassLoader getDefaultClassLoader()
ClassLoader
to pass to the first parameter of Proxy.newInstance()
if null
is passed as the second parameter to newProxy(Class[], ClassLoader)
.
This methods default implementation returns "getClass().getClassLoader()
",
but subclasses are free to override.
public void initializeProxy(java.lang.Object newProxy)
protected boolean doInvoke(java.lang.Object proxy, java.lang.reflect.Method method, java.lang.Object[] args, java.lang.Object[] result) throws java.lang.Throwable
JPUInvocationHandler
.
If autoDelegateToSelf()
returns true
, calls delegate(Object,Object,Method,Object[],Object[])
.
Returns whether the invocation was handled or not.
java.lang.Throwable
protected void doGetImplementedInterfaces(java.util.Collection dest)
dest
the Class
instances of any interfaces the generated proxy should implement,
in addition to those explicitly passed via the first parameter to
newProxy(Class[], ClassLoader)
.
|
||||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |