Java.next -- Four languages that represent the future of Java
Blogger Stuart Halloway has begun a series of posts on trends that point to the future of the Java platform. In his first post, he compares Clojure, Groovy, JRuby, and Scala -- four wildly different languages that nonetheless all play together in the JRE. Find out what unites these languages and what they can tell us about the future of Java-based development ...

Newsletter sign-up

Sign up for our technology specific newsletters.

Enterprise Java
View all newsletters

Email Address:

Generically chain dynamic proxies

Add AOP concepts to your application

Programming with plain-old Java objects (POJOs) is rather popular these days. When we program with POJOs, we can apply object-oriented programming (OOP) pretty easily. But sometimes implementing cross-cutting aspects throughout an application using OOP proves difficult. For example, generally implementing logging or security in our POJO business objects throughout an application is difficult to achieve with OOP. Dynamic proxies, which were introduced in J2SE 1.3, offer an easier solution.

The idea behind dynamic proxies is to include dynamic behavior around an object, yet neither change the object's existing code nor its interface. The famous Gang of Four (GoF) Decorator pattern provides a way to decorate an object (change its behavior) without changing the object code and allows us to add cross-cutting aspects to our business objects. Many existing frameworks and tools use this pattern. But when implementing static decorating, the pattern imposes some problems, which I discuss later in the article.

Prior to the introduction of dynamic proxies, there was no direct way to decorate objects dynamically. So vendors came up with tools to generate code automatically and decorate objects. Though a code-generation tool can help us generate static decorators, it requires extra steps and also introduces overhead for maintaining the generated code. By using dynamic proxies, we can greatly reduce this auto-generated code (perhaps to zero).

To see how dynamic proxies work, let's take an example of the classic Decorator pattern as a method interceptor and see what dynamic proxies can offer in its place. If we use dynamic proxies as is, we may face some coding complexities. Later in the article, you will see how to wrap these complexities involved with dynamic proxies and provide an abstraction over them. Most of the source code used in this article can be downloaded from Resources.

Static decorating and chaining without dynamic proxies

Suppose we have a simple business interface:

 public interface IMyBusinessObject {
   public String doExecute(String in);
}


And this implementation of a business object class:

 public class MyBusinessObject implements IMyBusinessObject {
   public String doExecute(String in) {
      System.out.println("Here in MyBusinessObject doExecute: input :" + in);
      return in;
   }
}


Now we want to add some behavior (e.g., logging) before and after the doExecute() method. The Decorator pattern helps us easily add this functionality.

We define an abstract decorator class like the following:

 public abstract class ADecorator implements IMyBusinessObject {
   protected IMyBusinessObject target;
   public void setTarget(IMyBusinessObject target_) {
      this.target = target_;
   }
   public ADecorator(){}
   public ADecorator(IMyBusinessObject target_) {
      setTarget(target_);
   }
}


Now we define a concrete DebugConcreteDecorator, which extends ADecorator. Our intention is to add debug messages before and after our business object's method invocation:

 public class DebugConcreteDecorator extends ADecorator {
   public String doExecute(String in) {
      System.out.println("DebugConcreteDecorator: before method : doExecute ");

String ret = target.doExecute(in); System.out.println("DebugConcreteDecorator: after method : doExecute "); return ret; } }


Now from the client code, we call our business object:

 IMyBusinessObject aIMyBusinessObject = new MyBusinessObject();
IMyBusinessObject wrappedObject = 
   new DebugConcreteDecorator(aIMyBusinessObject);
wrappedObject.doExecute("Hello World");


In the above code snippet, we wrap our business object with the DebugConcreteDecorator class instance. Since DebugConcreteDecorator extends ADecorator and ADecorator implements the business object interface IMyBusinessObject, the DebugConcreteDecorator class is itself an instance of IMyBusinessObject. First, we create an instance of MyBusinessObject. Next, we create an instance of DebugConcreteDecorator and pass the business object in the constructor. Since no constructor is in DebugConcreteDecorator, the constructor of its superclass (ADecorator) is called and the target object is set with the MyBusinessObject instance. So when the doExecute() method is called on the DebugConcreteDecorator instance, it first logs some debug message (using System.out) and then calls the business method on the actual business object (MyBusinessObject).

The above invocation's output is the following:

 DebugConcreteDecorator: before method : doExecute
Here in MyBusinessObject doExecute: input :Hello World
DebugConcreteDecorator: after method : doExecute



From this output, we observe that we are able to add the debug messages before and after the business method invocation.

We can also chain the decorators—call one decorator after another decorator—before invoking actual business methods. Let's define another decorator to show this approach:

 public class AnotherConcreteDecorator extends ADecorator {
   public String doExecute(String in) {
      System.out.println("AnotherConcreteDecorator: Going to execute method : doExecute");
      in = in + " Modified by AnotherConcreteDecorator";
      String ret = target.doExecute(in);
      System.out.println("AnotherConcreteDecorator: After execute method : doExecute");
      return ret;
   }
}


The above code snippet modifies the business method's input string parameter by adding an extra string (" Modified by AnotherConcreteDecorator") to it.

If we want to chain the decorators, we write the following code snippet in the client:

 IMyBusinessObject aIMyBusinessObject = new MyBusinessObject();
IMyBusinessObject wrappedObject =
   new AnotherConcreteDecorator (new DebugConcreteDecorator(aIMyBusinessObject));
wrappedObject.doExecute("Hello World");


In the above code snippet, we create a DebugConcreteDecorator instance by passing the actual target business object instance into it. Then we wrap the DebugConcreteDecorator instance with our new AnotherConcreteDecorator instance. So when the doExecute() method is called in the AnotherConcreteDecorator instance, AnotherConcreteDecorator first modifies the input parameter by adding the extra string. Then the call forwards to the DebugConcreteDecorator instance's doExecute() method. There, DebugConcreteDecorator logs the entry of the doExecute() method and calls the doExecute() method of the actual business object's doExecute() method.

Discuss

Start a new discussion or jump into one of the threads below:

Subject Replies Last post
. Generically chain dynamic proxies
By JavaWorld
1 04/05/08 06:01 PM
by Anonymous
. Great article
By Jongyun, Kim
0 07/23/07 05:48 AM
by Anonymous
. Great
By Anonymous
1 01/11/07 05:09 AM
by Anonymous
. Great article Srijeeb!!!
By sxdas3
0 02/02/06 04:44 PM
by Anonymous


Resources