Created
February 9, 2012 17:10
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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