Method invocation via proxy and reflection
A proxy object can implement any interface and then delegate
calls to anywhere.
I was able to use this once, but now I got a strange behavior
with Java 1.6 and java.lang.CharSequence.
One can see below that within the method ?invoke?, the method
is being ?redirected? to the method ?Base#length()?. Therefore,
the program should print ?363?.
This new invocation target is even printed (see ?### HERE ###?
in the source code below).
But actually ?Base#dummy0()? is called. (The output
of the program is given at the very end.)
I might have made some mistake. But in this case, I would
expect an exception or an error. Instead silently the wrong
method ?Base#dummy0()? is called. Why?
class Util
{
/** Return the field "clazz" of the class java.lang.reflect.Method.
@return the field "clazz" of the class java.lang.reflect.Method */
static java.lang.reflect.Field methodClassField()
{ final java.lang.reflect.Field fields[] =
java.lang.reflect.Method.class.getDeclaredFields();
for( int i = 0; i < fields.length; ++i )
{ if( fields[ i ].getName().equals( "clazz" ))
return fields[ i ]; }
throw new java.lang.RuntimeException
( "Can't find field \"clazz\" of class \"java.lang.reflect.Method\"." ); }}
/** Delegate class */
class Delegate
{ public int dummy0(){ return 147; }
public int dummy1(){ return 266; }
public int length(){ return 363; }
public int dummy3(){ return 473; }
public int dummy4(){ return 557; }}
class InvocationHandler0 implements java.lang.reflect.InvocationHandler
{ final private Delegate delegate;
java.lang.reflect.Field classField = Util.methodClassField();
public InvocationHandler0( final Delegate delegate )
{ this.delegate = delegate;
this.classField.setAccessible( true ); }
/** redirect call to delegate object */
public java.lang.Object invoke
( final java.lang.Object proxy,
final java.lang.reflect.Method method,
final java.lang.Object[] args )
throws java.lang.Throwable
{ java.lang.System.out.println( method ); // java.lang.CharSequence.length()
classField.set( method, this.delegate.getClass() );
java.lang.System.out.println( method ); // Base.length() ### HERE ###
return method.invoke( delegate, args ); }}
class Main
{ public static void main( final java.lang.String[] _ )
{
/* create and use a proxy ?v? to handle CharSequence-calls */
final Delegate delegate = new Delegate();
java.lang.ClassLoader cl = java.lang.CharSequence.class.getClassLoader();
java.lang.CharSequence v =
( java.lang.CharSequence )java.lang.reflect.Proxy.newProxyInstance
( cl, new Class[]{ java.lang.CharSequence.class },
new InvocationHandler0( delegate ));
java.lang.System.out.println( v.length() ); }}
/* The output is:
public abstract int java.lang.CharSequence.length()
public abstract int Delegate.length()
147
*/