23

I want to intercept all method invocations to some class MyClass to be able to react on some setter-invocations.

I tried to use dynamic proxies, but as far as I know, this only works for classes implementing some interface. But MyClass does not have such an interface.

Is there any other way, besides implementing a wrapper class, that delegates all invocations to a member, which is an instance of the MyClass or besided using AOP?

Tobias Hilka
  • 273
  • 1
  • 2
  • 5

7 Answers7

30

As you note, you cannot use JDK dynamic proxies (no interface), but using Spring and CGLIB (JAR included with Spring), you can do the following:

public class Foo
{
    public void setBar()
    {
        throw new UnsupportedOperationException("should not go here");
    }

    public void redirected()
    {
        System.out.println("Yiha");
    }
}

Foo foo = new Foo();
ProxyFactory pf = new ProxyFactory(foo);

pf.addAdvice(new MethodInterceptor()
{
    public Object invoke(MethodInvocation mi) throws Throwable
    {
        if (mi.getMethod().getName().startsWith("set"))
        {
            Method redirect = mi.getThis().getClass().getMethod("redirected");
            redirect.invoke(mi.getThis());
        }
        return null;
    }
});

Foo proxy = (Foo) pf.getProxy();
proxy.setBar(); // prints "Yiha"
Doug Porter
  • 7,721
  • 4
  • 40
  • 55
eljenso
  • 16,789
  • 6
  • 57
  • 63
14

If you are prepared to do something really ugly, have a look at:

http://docs.oracle.com/javase/7/docs/technotes/guides/jpda/

Basically the debugger interface ought to allow you to attach like a debugger, and hence intercept calls. Bear in mind I think this is a really bad idea, but you asked if it was possible.

Vikdor
  • 23,934
  • 10
  • 61
  • 84
Nick Fortescue
  • 43,045
  • 26
  • 106
  • 134
3

Java doesn't have any actual language features for method interception (not sure any static language does)

I kinda like Nick's idea of using the debugger interface, that's just mean.

I think the short answer you need is: No there isn't a way of intercepting a method call in Java without actually replacing the class using a proxy or wrapper.

Note: The AOP libraries just make this happen automatically.

Gareth Davis
  • 27,701
  • 12
  • 73
  • 106
1

I just developed a small framework for this purpose. You can check it out at: http://code.google.com/p/java-interceptor/ (use svn to check out).

1

Some of the Java gurus might frown upon this but I've had some good success with avoiding primitive types and setters altogether. My class looks like this:

class Employee extends SmartPojo {
    public SmartString name;
    public SmartInt age;
}

You'll notice two things: 1. everything is public. 2. No constructor.

The magic happens in SmartPojo which searches for any field which implements the "Smart" interface and initializes it. Since this is no primitive (and no final class), I can add set() and get() methods for all fields anywhere in my model in a single place. So no setter/getter wastes anymore, it's stunningly simple to add notification (also in a single place), etc.

True, this is no POJO anymore and it's not a Bean in most ways but I've found that these old ideas limit me more than they help. YMMV.

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
  • this is basically what grails does with their domain objects. Though, because they can implement it with groovy, its much nicer, and they wont need to have every property implementing a "smart" interface. – Chii Feb 23 '09 at 12:54
  • I needed a Java only solution. I've tried this with Groovy as well and, while the code is much more compact, this isn't as nice. I'm a huge fan of Groovy but I feel that 1.x is still a little bit ... "incomplete". – Aaron Digulla Feb 23 '09 at 13:35
0

There isn't a lot of magic in AspectJ. You can write your own agent. http://java.sun.com/javase/6/docs/api/java/lang/instrument/package-summary.html seems to be good starting point.

Miserable Variable
  • 28,432
  • 15
  • 72
  • 133
  • 2
    I think you underestimate the work needed for production quality agents. – Thorbjørn Ravn Andersen Feb 07 '11 at 11:31
  • Sorry, I did not mean to take away any credit from AspectJ. It is a wonderful thing and I am using it very successfully. I only meant to say that a simple agent for intercepting methods is not very difficult to write. Thanks for correcting me. – Miserable Variable Feb 08 '11 at 06:47
0
  1. Why cannot your class implement an interface? You could just extract some interface from it containing all the methods that you want to intercept and use the dynamic proxies mechanism easily. It's also a good programming practice to code with interfaces and not classes.

  2. You could use Spring framework with Spring AOP capabilities (which are using dynamic proxies inside) to do it. You will just have to define your class as a Spring bean in the configuration file and clients of your class will have to either get its instance from the Spring application context or as a dependency automatically (by defining the setMyClass(MyClass mc) method for instance). From there you can easily go to defining an aspect that intercepts all the method calls to this class.

Stas
  • 1,059
  • 2
  • 16
  • 26