Skip to content

Instantly share code, notes, and snippets.

@cessationoftime
Created February 9, 2012 17:10
Show Gist options
  • Save cessationoftime/1781224 to your computer and use it in GitHub Desktop.
Save cessationoftime/1781224 to your computer and use it in GitHub Desktop.
Javassist: create dynamic proxy to override methods of a class and record the method names as they are called
package edu.urmc.lis.datawarehousequery.schema.fieldbuilder.javassist
import javassist.util.proxy.ProxyFactory
import javassist.util.proxy.MethodHandler
import java.lang.reflect.Method
class MethodReaderProxy[T: Manifest] {
private var lastMethod: Option[Method] = None
private var methodManifest: Option[Manifest[_]] = None
private val clazz = manifest[T].erasure
def getMethodName: Option[String] = lastMethod.map(_.getName()) //return name of method invoked
def getMethodName[A: Manifest](method: (T) => A): String = {
methodManifest = Some(manifest[A])
method(proxy); //invoke method
lastMethod.map(_.getName()).get //return name of method invoked
}
def getMethodReturnType: Option[String] = methodManifest map (_.toString()) //return type of method invoked
def getMethodReturnType[A: Manifest](method: T => A) = {
methodManifest = Some(manifest[A])
method(proxy) //invoke method
methodManifest.get.toString()
}
val proxy = {
val factory = new ProxyFactory();
factory.setSuperclass(clazz);
factory.setHandler(new MethodHandler {
@throws(classOf[Throwable])
override def invoke(self: java.lang.Object, thisMethod: Method, proceed: Method, args: scala.Array[java.lang.Object]): java.lang.Object = {
lastMethod = Some(thisMethod)
def is[A: Manifest] = thisMethod.getReturnType() == manifest[A].erasure
if (is[Int] || is[Short])
0.asInstanceOf[AnyRef]
else if (is[Double]) (0.0).asInstanceOf[AnyRef]
else if (is[Option[_]]) None
else if (is[Unit] || is[Void]) Unit
else if (is[String]) ""
else throw new Exception("Unhandled type: " + thisMethod.getReturnType().toString())
}
});
val proxyClass: Class[T] = factory.createClass().asInstanceOf[Class[T]];
proxyClass.newInstance();
}
}
package edu.urmc.lis.datawarehousequery.schema.fieldbuilder.javassist
import org.junit.runner.RunWith
import org.specs2.mutable.Specification
import org.specs2.runner.JUnitRunner
import akka.actor.Scope
import edu.urmc.lis.datawarehousequery.schema.fieldbuilder.FieldAttributeMapping
import edu.urmc.lis.datawarehousequery.schema.lab.Orders
@RunWith(classOf[JUnitRunner])
class MethodReaderProxySpec extends Specification {
"MethodReaderProxy" should {
"Be able to proxy a table, and print out the name then returnType of called methods" in {
val fMap = new MethodReaderProxy[Orders]
fMap.getMethodName(_.abnormal_low) mustEqual "abnormal_low"
fMap.getMethodReturnType.get mustEqual "Int"
}
"Be able to proxy a table, and print out the returnType then name of called methods" in {
val fMap = new MethodReaderProxy[Orders]
fMap.getMethodReturnType(_.aotests_24) mustEqual "scala.Option[java.lang.String]"
fMap.getMethodName.get mustEqual "aotests_24"
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment