Monday, August 20, 2012

Getting object from calling method in Java

This is hardly production scenario, but at some point I wanted to find value of a variable from a caller class. Looks like this is not trivial task and is much more complicated than it should be (for some reason), however still possible.
Finding method and class name is easy via Thread class, but accessing real objects seems to be only possible with Java Debug Interface. For this purpose, application must be executed in debug mode (for grails it is with grails-debug command). There is no need for any additional library as everything is included into JDK and probably is used by JDK debugger.
General scenario is as folows:
  • connect with debugger provided with JDI via socket (there are other options, but sockets seems default for most tools)
  • spawn new thread where you will wait to do whatever you want to do with data on stack trace
  • suspend application at point where you want to do it
  • at the end of your work - continue application
There is example:

def att = com.sun.jdi.Bootstrap.virtualMachineManager().attachingConnectors().find{it instanceof}
Map arguments = att.defaultArguments()
com.sun.jdi.connect.Connector.Argument hostArg = arguments.get("hostname").setValue("localhost")
com.sun.jdi.connect.Connector.Argument portArg = arguments.get("port").setValue("5005")
com.sun.jdi.VirtualMachine vm = att.attach(arguments);
def thread = vm.allThreads().find {'main'}
def runnable = new Runnable() {
  void run() {
 while (!thread.isSuspended() ) {
 def frames = thread.frames().findAll {it.location().toString() =~ /grails.plugin.spock.test.listener.PerSpecRunListener:.*/}
 frames.each {frame->
   def res = frame.thisObject()
   def field = res.type().fieldByName("failureCount")
   if (field) {
       def countref = res.getValue(field).toString()
new Thread(runnable).start()