Smartproxy: a smart proxy creation library for Java

What is it?

Smartproxy is a library to dynamically create proxy classes and instances. This is similar to the java.lang.reflect.Proxy class but instead of forwarding the calls to an invocation handler, the smartproxy package use an underlying object to provide the default behavior and an abstract class to override some methods. The smartproxy approach, while less versatile than the jlrP one has a couple of advantages:

How does it work?

Basic principles

Suppose you want to proxify objects implementing the interface Underlying. You'll have to create an abstract Implementor class which will implement Underlying which will define the methods you want to override. The Implementor is also responsible for the storage of a reference to the underlying object and should also implement the ProxifiedObject interface in order to provide the getUnderlying method.

The smartproxy will create a proxy class extending ProxifiedObject and implementing Underlying. This class will implement the methods from Underlying underlying missing from the implementor as:

return method(parameters)
{
  return ((Underlying)getUnderlying()).method(parameters);
}

The gory details

So the smartproxy package actually creates a simple class forwarding to the underlying object the methods not in the implementor class. This could be done be automatically write the Java code, use javac to create the associated bytecode and then load it into the JVM. However this is quite unpractical since it requires a JDK instead of a JRE and may require to write temporary files (I didn't investigate much but I'm not sure that the javac API can work from memory directly). Furthermore I guess that the compilation process will be a big resource consumer. So instead of creating Java code, the smartproxy library directly writes bytecode to define the proxy classes or to be more accurate, uses the BCEL Library to perform this task.

Getting the software

Before the links a little warning:

This is alpha software and it may run, not run, crash your computer, etc. Beside as an alpha software the API may change between subsequent releases.

Binary and source archive can be found here in both tar.gz or zip format. The BCEL library is mandatory to use smartproxy but version 5.1 is included for convenience in both source and binary distributions.

Using it

Compilation

If you downloaded the binary distribution you can skip to the next point.

The source distribution provides an ant build file. I use the jikes compiler instead of javac so if you don't have it you can either download it or comment out the three lines in the build.xml file:

    <!-- Use jikes compiler, if you don't have it comment out the next lines -->
    <property name="build.compiler.emacs" value="true"/>
    <property name="build.compiler.pedantic" value="true"/>
    <property name="build.compiler" value="jikes"/>

The default target will build the smartproxy.jar and smartproxy-src.zip (To use with Eclipse as source for the jar). Other targets can be seen with ant -projecthelp.

If you want to be able to run the JUnit tests you'll have to copy get JUnit and copy the junit.jar file into the lib directory.

Installation

Untar/unzip the distribution archive and manage to get the bcel-5.1.jar and smartproxy.jar from the lib directory in the classpath, et voilą. The bcel-5.1.src.zip is provided as a convenience for Eclipse users but it may be useful with other IDEs. The use of the provided bcel jar is not mandatory but so far smartproxy had only been test with release 5.1 and won't probably work with earlier releases.

Basic Example

In this example, we assumed that you wanted to proxify objects implementing the SimpleInterface interface. This interface defines four methods called, a, b, c and d with various parameters. You first need to write an implementor class implementing SimpleInterface, ProxifiedObject and taking care of storing the underlying object:

public abstract class SimpleImplementor implements SimpleInterface, ProxifiedObject
{
   private SimpleInterface underlying;

   public SimpleImplementor(SimpleInterface underlying)
   {
      this.underlying = underlying;
   }

   public int a()
   {
      return 10000;
   }

   public String d(String x)
   {
      return "not" + x;
   }

   public Object getUnderlying()
   {
      return underlying;
   }
}

You can now create proxy using the following snippet:

// Create the proxy factory for the set on interface/implementor.
ProxyFactory factory = ProxyFactory.getInstance(SimpleImplementor.class, SimpleInterface.class);
// Creates an underlying object.
SimpleInterface base = new SimpleBaseClass();
// Proxify the underlying object.
SimpleInterface proxified = (SimpleInterface) factory.createProxy(new Object[] { base });

Documentation

The Javadoc API documentation is available in the distributions and online. Both binary and source distribution includes the source code for the JUnit tests and a few examples.

License

Smartproxy is distributed under the term of the BSD License and it used the BCEL Library developed by the Apache Software Foundation which is released under the terms of the Apache License.

Contact

Don't hesitate to contact me for anything relative to smartproxy (bug, suggestion, etc.).

Valid XHTML 1.1!