| |
"Under the Hood: java.lang.reflect.Proxy"
Vol. 7, Issue 2, p. 68
Listing 1: Issue interface: Issue.java
package com.dotcom;
public interface Issue
{
public void escalate( Person by, int amount );
public void resolve( Person by, String resolution );
public void defer( Person by, String resolution )
throws CannotDeferException;
public int getPriority( Person by );
}
Listing 2: Generic handler method: LoggingInvocationHandler.java
package com.dotcom;
import java.lang.reflect.*;
class LoggingInvocationHandler
implements InvocationHandler
{
private Class clazz;
private Object forObject;
public LoggingInvocationHandler( Class c, Object o )
{
this.clazz = c;
this.forObject = o;
}
public Object invoke( Object proxy,
Method method,
Object[] args )
throws IllegalAccessException,
InvocationTargetException
{
try
{
// execute the underlying method:
Object ret = method.invoke( forObject, args );
// log the call & return code:
LogManager.log(
clazz.getName(),
method.getName(),
args,
ret );
return( ret );
}
catch( InvocationTargetException ex )
{
// log the call & exception thrown:
LogManager.log(
clazz.getName(),
method.getName(),
args,
ex.getTargetException() );
throw ex;
}
}
}
Listing 3: Class capture: JVM_OnLoad
extern "C" JNIEXPORT jint JNICALL JVM_OnLoad(
JavaVM *jvm,
char *options,
void *reserved )
{
// read options into global base path variable
parseArguments( options );
// get a pointer to the JVMPI interface
if( jvm->GetEnv( (void **)&jvmpi, JVMPI_VERSION_1 ) < 0 )
{
trace( "Error enabling JVMPI\n" );
return JNI_ERR;
}
jvmpi->NotifyEvent = notifyEvent;
jvmpi->EnableEvent( JVMPI_EVENT_CLASS_LOAD_HOOK, NULL );
return JNI_OK;
}
Listing 4:
Class capture: notifyEvent()
void notifyEvent( JVMPI_Event *event )
{
if( event->event_type != JVMPI_EVENT_CLASS_LOAD_HOOK )
return;
//
// We're passed an event structure like:
//
// struct {
// unsigned char *class_data;
// jint class_data_len;
// unsigned char *new_class_data;
// jint new_class_data_len;
// void * (*malloc_f)(unsigned int);
// } class_load_hook;
unsigned char* class_data =
event->u.class_load_hook.class_data;
jint class_data_len =
event->u.class_load_hook.class_data_len;
// Leave the class unchanged
copyUnchangedClassBytes( event );
// Getting the name of a class from the class
// bytes isn't exactly straightforward, I'll
// spare you the details:
const char* path = getClassPath( class_data );
// make directories if necessary
ensurePathAvailable( path );
// Write out the class bytes as we were given them
FILE* f = fopen( path, "wb" );
delete[] const_cast<char*>( path );
path = 0;
if( !f ) return;
fwrite( class_data, class_data_len, 1, f );
fclose( f );
}
Listing 5: Decompiled proxy class: $Proxy0.java
import com.dotcom.Issue;
import com.dotcom.Person;
import java.lang.reflect.*;
public final class $Proxy0
extends Proxy implements Issue
{
public $Proxy0(InvocationHandler h)
{
super( h );
}
private static Method m_defer =
Issue.class.getMethod(
"defer",
new Class[] { Person.class, String.class }
);
private static Method m_escalate =
Issue.class.getMethod(
"escalate",
new Class[] { Person.class, Integer.TYPE }
);
private static Method m_getPriority =
Issue.class.getMethod(
"getPriority",
new Class[] { Person.class }
);
private static Method m_resolve =
Issue.class.getMethod(
"resolve",
new Class[] { Person.class, String.class }
);
private static Method m_hashCode =
Object.class.getMethod(
"hashCode",
new Class[0]
);
private static Method m_toString =
Object.class.getMethod(
"toString",
new Class[0]
);
private static Method m_equals =
Object.class.getMethod(
"equals",
new Class[] { Object.class }
);
public final void defer(Person p, String s)
throws CannotDeferException
{
try
{
h.invoke(
this,
m_defer,
new Object[] { p, s } );
}
catch( Error err ) { throw err }
catch( RuntimeException rte ) { throw rte; }
catch( CannotDeferException cde ) { throw cde; }
catch( Throwable t )
{
throw new UndeclaredThrowableException( t );
}
}
public final void escalate(Person p, int i)
{
try
{
h.invoke(
this,
m_escalate,
new Object[] { p, new Integer( i ) } );
}
catch( Error err ) { throw err; }
catch( RuntimeException rte ) { throw rte; }
catch( Throwable t )
{
throw new UndeclaredThrowableException( t );
}
}
public final int hashCode()
{
try
{
return (
(Integer) h.invoke(
this,
m_hashCode,
null )
).intValue();
}
catch( Error err ) { throw err; }
catch( RuntimeException rte ) { throw rte; }
catch( Throwable t )
{
throw new UndeclaredThrowableException( t );
}
}
public final String toString()
{
try
{
return (String)
h.invoke( this, m_toString, null );
}
catch( Error err ) { throw err; }
catch( RuntimeException rte ) { throw rte; }
catch( Throwable t )
{
throw new UndeclaredThrowableException( t );
}
}
public final boolean equals(Object o)
{
try
{
return (
(Boolean) h.invoke(
this,
m_equals,
new Object[] { o } )
).booleanValue();
}
catch( Error err ) { throw err; }
catch( RuntimeException rte ) { throw rte; }
catch( Throwable t )
{
throw new UndeclaredThrowableException( t );
}
}
public final int getPriority(Person p)
{
try
{
return (
(Integer) h.invoke(
this,
m_getPriority,
new Object[] { p } )
).intValue();
}
catch( Error err ) { throw err; }
catch( RuntimeException rte ) { throw rte; }
catch( Throwable t )
{
throw new UndeclaredThrowableException( t );
}
}
public final void resolve(Person p, String s)
{
try
{
h.invoke(
this,
m_resolve,
new Object[] { p, s }
);
}
catch( Error err ) { throw err; }
catch( RuntimeException rte ) { throw rte; }
catch( Throwable t )
{
throw new UndeclaredThrowableException( t );
}
}
}
|
|