Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Capture method calls in Java

Tags:

java

methods

I need to capture a method call in Java and I do not want to use JPDA or JDI; I want it to happen in the original JVM.

For instance:

public class A {
  public void m() {}
}

public class Main {
  public static void main(String[] args) {
    A a = new A();
    a.m();
  }
}

I do not want to actually let the method execute at the time, but need to capture it and schedule it in a queue. Thus, AOP will not help me in this regard. I thought about proxying the method. Something such as:

public class A {
  public void m() {
     methodQueue.add(new MethodInvocation() {
          public void invoke() {m_orig();}
     });
  }
  private void m_orig(){}
}

Any ideas? Thanks so much in advance.

like image 899
nobeh Avatar asked Jan 25 '11 14:01

nobeh


People also ask

What is caller call method in Java?

The calling method is the method that contains the actual call. The called method is the method being called. They are different. They are also called the Caller and the Callee methods. For example int caller(){ int x=callee(); } int callee(){ return 5; }

Which is the preferred way to intercept Java calls?

Defining Interceptors The preferred way to define in Java code is by using meta-data annotations. They can be defined in the application descriptor as well, but, in that case they are not portable across Java EE servers. Some of the meta-data annotations found in the javax.


2 Answers

You can use a technique called Dynamic Proxies in Java. They are described in detail in the following document: Dynamic Proxies

The solution for your problem would then be (with little changes necessary):

public interface A { void m(); }

public class AImpl implements A { public void m() {} }

public class EnqueueProxy implements java.lang.reflect.InvocationHandler {

    private Object obj;

    public static Object newInstance(Object obj) {
        return java.lang.reflect.Proxy.newProxyInstance(
            obj.getClass().getClassLoader(),
            obj.getClass().getInterfaces(),
            new EnqueueProxy(obj));
    }

    private EnqueueProxy(Object obj) {
        this.obj = obj;
    }

    public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
        try {
            MethodQueue mq = ... // get the queue from where you want
            mq.add(new MethodInvocation(obj, m, args)
        } catch (InvocationTargetException e) {
            throw e.getTargetException();
        } catch (Exception e) {
            throw new RuntimeException("unexpected invocation exception: " + e.getMessage());
        }
            return null;
    }
}

Then construct a EnqueueProxy for an implementation of the A interface and call the m method:

A a = (A) EnqueueProxy.newInstance(new AImpl());
a.m();
like image 116
paweloque Avatar answered Sep 26 '22 03:09

paweloque


Looks like you would also be happy with a queue of Callables.

like image 30
Volker Stolz Avatar answered Sep 23 '22 03:09

Volker Stolz