Java validation with dynamic proxies(IBM)

Java validation with dynamic proxies

Decouple validation processes from your business object implementations

developerWorks
Document options
Set printer orientation to landscape mode

Print this page

<script language="JavaScript" type="text/javascript"> </script>
Email this page

E-mail this page

Sample code


Rate this page

Help us improve this content


Level: Introductory

Eric Olson ([email protected]), Software Engineer, Lakeview Technologies

14 Sep 2004

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.
<script language="JavaScript" type="text/javascript"> </script>

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 proxies can help you improve on both.

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


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


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.



Back to top


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


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:

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.

  • 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.



Back to top


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.

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.

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.



Back to top


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


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.



Back to top


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


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.



Back to top


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


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.



Back to top


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.



Back to top


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.



Back to top


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.




Back to top


Download

Name Size Download method
j-dynproxies-source.zip   FTP
Information about download methods Get Adobe® Reader®


Back to top

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章