///Java Validation With Dynamic Proxies

Java Validation With Dynamic Proxies

Decouple validation processes from your business object implementations

Version 1.3 of the Java platform saw the introduction of the dynamic proxy facility. Dynamic proxies offer many interesting solutions to Java developers, including a validation scheme that easily decouples validation logic from an application’s core business logic. In this article, Java developer Eric Olson shows you how dynamic proxies can keep your core application code free of validation routines and focused solely on business logic.

Validation is an essential aspect of many enterprise applications. Most business methods contain validation logic to ensure that pre-conditions are met before carrying out business logic. Code that deals with values entered through a user interface employs validation logic to ensure that the values entered by a user are valid before carrying out actions that may affect other areas of the application or other users. Validation is an especially important component of applications that employ and interact with other loosely coupled components, as well as services that may not be strict in their assertions.

As important as it is to the safety and functionality of your business applications, core application logic is often cluttered with validation routines. Validation processes are often scattered throughout method calls, making it difficult to tell the difference between validation logic and core business logic. In most cases, business objects and methods must know some details of the validation process and deal with them directly in their implementation — for example, a business object may throw a validation exception directly from the business method (either coded directly in the method, or as a result of calling some validation service). The validation exception in this case is really a byproduct of the validation process, however, and would ideally be hidden from the business object implementation.

In this article, I’ll show you a more decoupled and centralized approach to validation, using the dynamic proxy facility introduced to the Java platform with version 1.3. Working with a single example throughout the article, I’ll demonstrate the weaknesses of both tightly coupled and loosely coupled validation schemes, and then show you how dynamic

Tightly coupled validation

Throughout this article, I’ll work with a simple User object that defines methods for dealing with a user in a system. Listing 1 presents the User interface and its methods.

Listing 1. User and its methods

/**

* Gets the username of the User.
*/
String getUsername();

/**
* Sets the username of the User.
* @throws ValidationException indicates that validation of the proposed
* username variable failed. Contains information about what went wrong.
*/
void setUsername(String username) throws ValidationException;

/**
* Gets the password of the User.
*/
String getPassword();

/**
* Sets the password of the User.
* @throws ValidationException indicates that validation of the proposed
* password variable failed. Contains information about what went wrong.
*/

void setPassword(String password) throws ValidationException;

In a tightly coupled data validation scheme, I would insert validation code directly into the interface’s method implementations, as shown in Listing 2. Note that the validation logic is hardcoded into the method before the instance variable is set.

Listing 2. A tightly coupled validation scheme

public void setPassword(String password) throws ValidationException {

if ((password == null) || (password.length() < MIN_PASSWORD_LENGTH)) {
throw new ValidationException("INVALID_PASSWORD",
"The password must be at least " +
MIN_PASSWORD_LENGTH +
" characters long");
}

this.password = password;
}

In this example, the validation logic is tightly coupled to the object in which it’s being used. The weaknesses of this approach should be fairly obvious:

* It doesn’t introduce any reusable validation code. Although the example contains length and null checks that I could use in many other areas of the application, they’re coded in such a way that they cannot be reused.

* The validation rules aren’t configurable in any way. If I ever wanted to add another validation rule to the setPassword() method, for example, I would have to change the method itself, recompile, and possibly redeploy.

Although not ideal, tightly coupled validation code is quite common, particularly in older applications. Fortunately, tight coupling isn’t the only option when it comes to coding the User interface’s validation logic.

Loosely coupled validation

You can get around tight coupling by having the interface implementation call a separate service to perform its validation logic . Typically, this service will have a set of validation rules assigned to specific methods on specific objects. Because the validation rules are decoupled from the interface’s business logic, they can be reused across many methods on many objects. You can also define the validation rules externally, in which case changing the validation logic will be a matter of changing the validation service’s configuration.

Listing 3 shows how a validation service can be used to decouple validation logic from the implementation’s core business logic.

Listing 3. Using a validation service

public void setPassword(String password) throws ValidationException {

BusinessObjectValidationService.validate(this, "setPassword",
new Object[] {password});

this.password = password;
}

Here, the validation logic is run as part of a service external to the object that is calling it. Specifically, validation performed on the setPassword() method is configured to a validation service rather than in the method itself. This type of loose coupling can, in many cases, address the weaknesses in the previous example:

* Validation rules are potentially reusable as they may be written once and defined to many methods on different objects. For instance, I could write a validation rule asserting that a given parameter was not null and then reuse it across all methods needing the same rule.

* Validation rules are potentially configurable. For example, I could initialize the validation service with an XML document describing the rules to run for specific methods and objects. I could also expose an API into this configuration, which would let me change validation rules at runtime.

Although a step in the right direction, this approach still has some drawbacks. When I developed the method, I had to be sure to call the validation service and ensure that the method implementation declared its ValidationException. These are artifacts of the validation service that don’t have anything to do with the core logic of the method. What I really want is a way to write the User interface implementation so that it doesn’t need to know these sorts of things.

What about code generation tools?

Developers sometimes use code generation tools to insert boilerplate validation code into business methods. Like the dynamic proxy approach, code generation tools let you write your implementation code free of validation concerns. The difference between the two approaches is that, unlike dynamic proxies, generated code is always present in business objects and cannot be switched out with another implementation, such as an invocation handler. Using dynamic proxies allows you to change invocation handlers at runtime without recompiling the code or redeploying the application.

The dynamic proxy approach

Dynamic proxies are classes that implement a set of interfaces specified at runtime. Method invocations on a proxy class are dispatched to an invocation handler that is specified when the proxy class is generated. Dynamic proxy classes have many interesting uses within an application, one of which is to effectively handle pre- and post-method invocation operations in a uniform fashion. Because validation is often a pre-method invocation operation, dynamic proxies provide us with a solution to the problems outlined in the previous examples. Dynamic proxy classes give us a way to easily handle validation on any method in a uniform way, while completely separating all of the validation logic from the core business logic.

Because interfaces already exist for the main business objects and services in many frameworks, you’ve likely had experience with swapping in and out different implementations of such interfaces. Using dynamic proxy classes is very similar, but instead of dealing directly with an implementation of the interface, clients deal with a proxy class that implements the interface, performs the desired validation, and delegates method calls through to an implementation class. With the dynamic proxy approach, all validation logic should be transparent to the clients of the proxied classes. As a result, implementing the new validation scheme should be fairly simple: I won’t need to change a single line of the code that uses the User interface.

Conceptually, I’ll create a custom invocation handler class that performs the validation rules. The invocation handler will contain an instance of a real implementation class as an instance variable. It will first validate method parameters upon a method invocation and then delegate the method call to the implementation class. When the application needs a business object instance, it will actually receive an instance of the dynamic proxy class. As you’ll see in a moment, this allows the business object implementation class to remain completely independent of any code specific to the validation processes.

A note about interfaces

Dynamic proxy classes are generated with a list of interfaces to implement. For the purposes of this article, I’ll use the User interface, although generally, you’ll need to be sure that you’ve defined interfaces for any of the methods you want validated this way.

The invocation handler

The invocation handler class is where all of the data validation logic is handled. The invocation handler class will also delegate method calls to a real implementation class in order to process the core business logic. Listing 4 shows an invocation handler that is not tied to any specific business object, and could therefore be used along with any business object that needs to be validated. Notice how the validation code in the invoke() method below is nearly identical to the code from Listing 3; in fact, I could use the same validator service here as I did earlier.

Listing 4. The invocation handler

/**

* This is the object to which methods are delegated if they are not
* handled directly by this invocation handler. Typically, this is the
* real implementation of the business object interface.
*/
private Object delegate = null;

/**
* Create a new invocation handler for the given delegate.
* @param delegate the object to which method calls are delegated if
* they are not handled directly by this invocation handler.
*/
public BusinessObjectInvocationHandler(Object delegate) {
this.delegate = delegate;
}

/**
* Processes a method call.
* @param proxy the proxy instance upon which the method was called.
* @param method the method that was invoked.
* @param args the arguments to the method call.
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {

// call the validator:
BusinessObjectValidationService.validate(proxy, method.getName(), args);

// could perform any other method pre-processing routines here...

/* validation succeeded, so invoke the method on the delegate. I
only catch the InvocationTargetException here so that I can
unwrap it and throw the contained target exception. If a checked
exception is thrown by this method that is not assignable to any of
the exception types declared in the throws clause of the interface
method, then an UndeclaredThrowableException containing the
exception that was thrown by this method will be thrown by the
method invocation on the proxy instance.
*/
Object retVal = null;
try {
retVal = method.invoke(delegate, args);
} catch (InvocationTargetException ite) {
/* the method invocation threw an exception, so "unwrap" it and
throw it.
*/
throw ite.getTargetException();
}

// could do method post-processing routines here if necessary...

return retVal;
}

As you can see, this implementation of the invocation handler makes use of a generic validator service, the same as in Listing 3. For an alternative solution, I could have created an invocation handler that looks more like the one from Listing 2, where the validation code is run directly in the invocation handler. In this case, I would have used the invocation handler itself to check whether the method called was the setPassword() method and length and null checks would happen directly in the handler. While this approach works to decouple the interface’s validation logic from its core business code, it isn’t very reusable or configurable. I’ll continue with the generic-validator implementation in the next section, where you’ll really begin to see the value of reusable and reconfigurable code.

The business object implementation

The next step is to specify a business object implementation to the constructor of the invocation handler. For the purpose of this example I’ll use a validation-free implementation of the User interface, because the validation logic is being handled in the invocation handler. The relevant code from the implementation class is shown in Listing 5.

Listing 5. The validation-free User implementation

/**

* The username of this User.
*/
private String username = null;

/**
* The password of this User.
*/
private String password = null;

/**
* Gets the username of the User.
*/
public String getUsername() {
return username;
}

/**
* Sets the username of the User.
*/
public void setUsername(String username) {
this.username = username;
}

/**
* Gets the password of the User.
*/
public String getPassword() {
return password;
}

/**
* Sets the password of the User.
*/
public void setPassword(String password) {
this.password = password;
}

If you compare the setPassword() method body above to that in Listing 2, you will see that it contains no code specific to validation. The details of the validation process are now handled entirely by the invocation handler.

The business object factory

I can tie all this together with one final piece of code, which will actually create the dynamic proxy classes and attach the correct invocation handler to it. The simplest approach is to encapsulate the creation of the proxy class within the Factory pattern.

Many business object frameworks employee a Factory pattern to create concrete implementations of their business object interfaces, such as the User interface. Creating a new business object instance is, therefore, simply a matter of calling a factory method: All the details behind the creation of the object are left up to the factory, and clients remain ignorant of how the implementation is actually constructed. Listing 6 shows how to create a dynamic proxy class for the User interface (using the UserImpl implementation class), while passing all method invocations through the invocation handler.

Listing 6. The UserFactory

/**

* Creates a new User instance.
*/
public static User create() {
return(User)Proxy.newProxyInstance(User.class.getClassLoader(),
new Class[] {User.class},
new BusinessObjectInvocationHandler(new UserImpl()));
}

Notice that the Proxy.newProxyInstance() method takes three arguments: the classloader in which the dynamic proxy class is defined; the Class array that contains all the interfaces the dynamic proxy class will implement (I’ve only implemented the User interface in the factory, although I could specify any interfaces that I wanted to implement); and the invocation handler to handle the method invocations. I’ve also created a new instance of the UserImpl implementation class and passed it to the invocation handler. The invocation handler will use the UserImpl class to delegate all business method invocations.

Drawbacks of dynamic proxies

Unfortunately, using dynamic proxy classes does have one major drawback: performance. Method invocations on dynamic proxy classes do not perform nearly as well a direct method call on objects. Therefore, your use of dynamic proxies in an application framework depends on what is more important to you: cleaner architecture or better performance. In many areas of an application, the performance drawback may be worth it, while in other areas performance is critical. One solution, therefore, is to use dynamic proxies in some areas and not in others. If you decide to go this route, keep in mind that the invocation handler can perform other operations besides validation, allowing you to change the behavior of your business objects at runtime or after code has been deployed.

Other uses for dynamic proxies

Dynamic proxy classes have many uses within a business object framework other than simply validating methods in a uniform way. The simple invocation handler I built could be used for any pre- and post-method invocation processing. For example, I could easily take business method timings by inserting code before and after the business object implementation method calls to measure elapsed time. I could also notify interested listeners about state changes by inserting some post-method invocation logic.

Using beans for validation

In addition to the approach discussed in this article, you can use the constrained properties facility of the JavaBeans architecture for validation. In a nutshell, before a constrained property is changed, any number of interested listeners are notified. If any of the listeners do not approve of the change, it may throw a java.beans.PropertyVetoException exception, which signals that the property change is not acceptable.

This model actually works well with dynamic proxy classes because the entire messaging mechanism can be built into the invocation handler. As with the approach described in this article, the real business object implementation does not need to know or care what type of validation is being done. In fact this sort of validation could be introduced later without changing any of the method implementations involved with a constrained property.

In the example, I created the dynamic proxy class for a single interface: User. I could just as easily specify multiple interfaces that the dynamic proxy class would implement at runtime. In this way, the object returned from the static factory method could implement any number of interfaces defined when I create the proxy. The invocation handler class must know how to deal with method invocations of all the interface types.

You should also notice in the example that I always call an actual implementation class to perform the business logic. This does not have to be the case. For example, the proxy class could delegate the method invocation to any other object or even handle it itself. A simple example of this is that I have an interface that exposes a number of JavaBeans properties via set/get methods. I also create a specialized invocation handler that holds on to a Map where the key is the property name, and the value is the value of the property. On a get call, I simply return the value from the Map; on a set call, I replace the value held in the Map, alleviating need to write code for these simple JavaBean class implementations.

Conclusion

Using dynamic proxy classes for validation is a simple and effective way to decouple validation routines from your application’s core business logic. Unlike a tightly coupled approach, using dynamic proxies leaves you with validation code that is reusable and configurable.

In this article, you saw the benefits of using dynamic proxies with an invocation handler. Because the method invocations on the dynamic proxy classes were all channeled through a common invocation handler, you could very easily change the logic performed by the handler, even in already deployed code or dynamically at runtime. The invocation handler could also be refactored to handle other operations across multiple method invocations on different object types.

The Java platform’s dynamic proxy facility is not your only option for decoupling validation routines from business logic in your core code. In some cases, such as where performance is the most important factor in the application, it may not even be the best option. While this article focused on dynamic proxies, I did discuss some other options, including the JavaBeans constrained properties facility and the use of code generation tools. As with any technology, you should carefully evaluate the alternatives and use dynamic proxies only when they are the best solution for your application.

Resources

• Click on the Code icon at the top or bottom of this article to download the source code used in this article.

• John Zukowski shows you another use for dynamic proxies, with his column on ” Dynamic event listener proxies” ( developerWorks, October 2003).

• Brett McLaughlin’s ” The fine points of data validation” ( developerWorks , December 2002) explains how to get the best performance out of your validation code.

• Whereas this article focused on business-specific validation, Brett’s column on ” Validation helper classes” ( developerWorks, January 2003) shows you how to avoid code redundancy in data-format validation.

• Learn about using the JavaBeans constrained properties facility for validation, with Victor Okunev’s ” Validation with pure Java” ( JavaWorld , December 2000).

• On the flipside of the coin, Brett McLaughlin’s ” Validation with Java and XML Schema” ( JavaWorld, September 2000) explains why Java code isn’t a complete solution for data validation.

• Dennis Sosnoski’s ” Data binding, Part 1: Code generation approaches — JAXB and more” ( developerWorks , January 2003) is a survey of XML data binding frameworks that support Java language code generation.

• Visit Sun Microsystems’s Dynamic Proxy API home page to learn more about dynamic proxies.

• You’ll find articles about every aspect of Java programming in the developerWorks Java technology zone.

• Also see the Java technology zone tutorials page for a complete Listing of free Java-focused tutorials from developerWorks.

• Visit the Developer Bookstore for a comprehensive Listing of technical books, including hundreds of Java-related titles.

• Interested in test driving IBM products without the typical high-cost entry point or short-term evaluation license? The developerWorks Subscription provides a low-cost, 12-month, single-user license for WebSphere®, DB2®, Lotus®, Rational®, and Tivoli® products — including the Eclipse-based WebSphere Studio IDE — to develop, test, evaluate, and demonstrate your applications.

2010-05-26T11:20:14+00:00 May 14th, 2005|Java|0 Comments

About the Author:

Eric Olson is a software engineer at Lakeview Technologies, which specializes in high availability, disaster recovery, clustering, and data replication infrastructure software and services. He has developed in the Java programming language for over six years, and has worked with many different business object frameworks including EJB technology and IBM WebSphere business components.

Leave A Comment