Print
Dimple Tips

Tips for Java 1.3 and above

  1. When you are using dimple in production code for interceptor, it is normally better to cache an Implementor object for repeated use, as constructing Implementor takes some CPU cycles. For the interceptor example in Home, one can make it more performant by doing:
    public class NonCloseable {
      public void close(){}//suppress close().
    }
    //Implementor is immutable, so safe to share.
    private static final Implementor closeSuppresser = new Implementor(NonCloseable.class);
    ...
    Connection realConn = ...;//wherever you get it from
    Connection intercepted = (Connection)closeSuppresser.implement(Connection.class, 
      new NonCloseable(), realConn);
    
    //Hey, untrusted, you will never be able to close me!
    callTheUntrustedCode(intercepted);
    ...
    //Because I want to close it myself.
    realConn.close();
  2. dimple uses reflection to call the interceptor methods. SecurityException could be thrown if a SecurityManager is installed and prevents the code from calling public methods defined in non-public class (including anonymous class).

    If you are concerned about this, always use an explicit public class to define interceptor methods.
  3. dimple can also be used to dynamically override a class (as long as the class is not final and has a public default constructor). You would need cglib in the classpath though. For example:
    SomeClass realSomeObj = ...;//whatever it is
    SomeClass intercepted = (SomeClass)closeSuppresser.implement(SomeClass.class, 
      new NonCloseable(), realSomeObj);
  4. When any of "equals()", "hashCode()" and "toString()" is not explicitly declared by the interceptor class, dimple will forward the corresponding method call to the delegated object.

Generics

When using dimple for Java 5, generics is used so that you do not need to down-cast. The above non-closeable connection example can become:

...
private static final Implementor<NonCloseable> closeSuppresser = Implementor.instance(NonCloseable.class);
Connection realConn = ...;//wherever you get it from
Connection intercepted = closeSuppresser.implement(Connection.class, 
  new NonCloseable(), realConn);
...

Stronger type

When using dimple to implement or override, the compiler doesn't check the method signature for you. When you have a typo or something so that the impl method does not match the method you are trying to implement, (parameters are not even contravariant), your method will not be used. For example:

Connection nonCloseable = Implementor.proxy(Connection.class, new Object(){
  public void cloze(){}//Oops, Typo!
}, realConn);

The close method will not be intercepted at all.

Normally such error is not hard to find as your unit test case would fail anyway.

However, when you do want to make sure that the method is used, use the Implementor.implementedBy() or Implementor.willImplement() methods to perform additional type checking. For example:

Connection nonCloseable = Implementor.proxy(Implementor.implementedBy(Connection.class, NonCloseable.class), new NonCloseable(), realConn);

or

Implementor closeSuppresser = new Implementor(Implementor.willImplement(NonCloseable.class, Connection.class));
Connection nonCloseable = (Connection)closeSuppresser.implement(Connection.class, new NonCloseable(), realConn);

In Java 5, the @Implement annotation can be used to annotate the method or the entire class to ask dimple runtime to check against such error.

Using @Implement, the above code will become:

Connection nonCloseable = Implementor.proxy(Connection.class, new Object(){
  @Implement
  public void cloze(){}//fail fast for this typo
}, realConn);

And you will get an UnusedMethodException right away.

Powered by Atlassian Confluence