In a business process, you often have attributes that must not be null and other attributes that could be optional. In the case of attributes that must be an instance, you have to implement a check similar to this:
if( attribute1 == null )
{
throw new Attribute1IsNullException()
}
If the value object has N attributes, you will get something like this:
if( attribute1 == null )
{
throw new Attribute1IsNullException()
}
if( attribute2 == null )
{
throw new Attribute2IsNullException()
}
...
if( attribute N == null )
{
throw new AttributeNIsNullException()
}
The result: A lot of if statements! And you have to type them all!
Now imagine that the number of validations increases from 10 to 25 because 15 new use cases must be implemented in the next iteration. Unnerving isn't it? An effective way to reduce these checks is to move all of them from the value object class into the value object's validating class.
YOU MIGHT ALSO LIKE
TIP
ObjectStreamClass: Peeking at a Java Object's Serialization
HttpClient basic authentication
FEATURE
Java programming with lambda expressions
Daily updates on enterprise Java news, tips and techniques
At this point, you might recognize that you always perform the same checks. The only difference is the name and type of the attribute. In most cases, the type is not of interest because the compiler checks it. An important point is to be sure that the methods receiving the attribute's value all start with the same name. In our case above, this would be get.
Calling all the value object's getters by reflection is easy. If you use Eclipse, for example, you can generate the get/set methods for all attributes. So for our attribute1, the getter will be getAttribute1() and the setter, setAttribute1(Integer attributeValue), if attribute1 is an integer attribute. If these preconditions are given, you can think about a generic solution. This article explains how a generic solution could be realized using reflection and the Visitor pattern.
The framework's classes and interfaces
The following class diagram shows the relationships between the classes and interfaces used for building our generic validation framework.
Class diagram
Note: You can download these classes and interfaces from Resources.
Validateable interface
The Validateable interface complements the Visitable interface. The defined method validateWith() is the analog method to the accept() method in the Visitor pattern's Visitable interface. With the validateWith() method, you can validate the value object with different validators because this method takes an implementation of the IClassAttributeValidator interface as a parameter.
IClassAttributeValidator interface
the IClassAttributeValidator interface is the counterpart of the Visitor interface in the Visitor pattern. And its validate(AbstractParameter param) method is the counterpart of Visitor's visit(object SomeObject) method. The validate() method's AbstractParameter parameter type lets you access (validate) all parameters that are subtypes of the class AbstractParameter. In addition, using this interface in the validateWith() method as a parameter allows us to change the implementation of the used validator in the future for parameters that need a different validation—for example, testing the parameter attributes for a defined value range in addition to the null checks.
RESOURCES
WHITE PAPER
APM in the Age of Hybrid Cloud: Ten Key Findings by EMA
WHITE PAPER
Open Source, Java and ready to go...Download Bonita BPM to automate processes now.
WHITE PAPER
A Smarter Approach to CRM: An IBM Perspective
WHITE PAPER
5 Unsung Tools of DevOps
MORE RESOURCES
AbstractParameter
The AbstractParameter class implements the validateWith() method from the Validateable interface. This implementation is, as you can see in the code snippet below, very simple. The method just calls the validate() method in the given validator and submits the parameter object to the validator:
public void validateWith( IClassAttributeValidator validator ) throws Exception
{
validator.validate( this );
}
Also, the AbstractParameter implements some often used additional methods. The protected method addOptionalMethod() lets all subtypes add an optional method to optionalGetAttributeMethods HashMap(). Deriving from AbstractParameter enables you to factor out such getters that may deliver null. As you can imagine, you can add optional methods, for example, in the constructor of the value object that derives from AbstractParameter.
The isOptionalMethod() method is used to verify whether the attribute should be checked.
The toString() method is implemented for convenience because value objects consist of many attributes. So in the subtypes of AbstractParameter, it's not necessary to do a lot of System.out.printlns in the implementation. This method also uses reflection to do its job.
GenericClassAttributeValidator
The GenericClassAttributeValidator class implements the IClassAttributeValidator interface with the method validate(). The class is implemented as a singleton. validate()'s implementation looks like this:
public synchronized void validate( AbstractParameter param ) throws AttributeValidatorException
{
Class clazz = param.getClass( );
Method[] methods = clazz.getMethods( );
//Cycle over all methods and call the getters!
//Check if the getter result is null.
//If result is null throw AttributeValidatorException.
Iterator methodIter = Arrays.asList( methods ).iterator( );
Method method = null;
String methodName = null;
while ( methodIter.hasNext( ) )
{
method = (Method) methodIter.next( );
methodName = method.getName( );
if ( methodName.startsWith( "get" ) &&
clazz.equals( method.getDeclaringClass( ) ) &&
!param.isOptionalMethod( methodName ) )
{
Object methodResult = null;
try
{
methodResult = method.invoke( param, null );
}
catch ( IllegalArgumentException e )
{
throw new AttributeValidatorException( e.getMessage( ) );
}
catch ( IllegalAccessException e )
{
throw new AttributeValidatorException( e.getMessage( ) );
}
catch ( InvocationTargetException e )
{
throw new AttributeValidatorException( e.getMessage( ) );
}
if ( methodResult == null )
{
String attributeName = methodName.substring( 3, 4 ).toLowerCase( ) +
methodName.substring( 4, methodName.length( ) );
String className = clazz.getName( );
className = className.substring( className.lastIndexOf( '.' ) + 1 );
Integer errorNumber = new Integer( 1000 );
throw new AttributeValidatorException( "Error: " + errorNumber + " "
+ attributeName + " in " + className +" is null!!!");
}
}
}
}
First, as you can see in the code, we get all methods from the value object. After that, we cycle over this collection of methods. If the method starts with a get, is a subtype of AbstractParameter, and not optional, we call the getter via reflection and check its result. If the result is null, this is an error, and if not, everything is all right. The optional methods and the derived methods from the superclass are not called.
Testing our classes
Now that we have implemented all the classes and interfaces we need, we must do some tests to check if everything works. To do that, we implement a little test class with a main() method to start the test.
TestParameter
The TestParameter class is derived from AbstractParameter and includes some private attributes that should be validated: simply four Integer attributes.
Optional attributes
To verify that optional attributes are not tested, we define the getter for attribute testParam3 as optional. For this reason, we enter this getter in the map of optional methods in the superclass AbstractParameter via addOptionalMethod(methodName) in TestParameter's constructor.
How the validation framework works
For the test, we now fill the TestParameter class in the following way:
TestParameter param = new TestParameter( );
param.setTestParam1( new Integer( 1 ) );
param.setTestParam2( new Integer( 2 ) );
param.setTestParam3( new Integer( 3 ) );
param.setTestParam4( new Integer( 4 ) );
As you can see, four Integer attributes are filled with Integer 1, 2, 3, and 4. To validate we just have to call:
param.validateWith( GenericClassAttributeValidator.getInstance( ) );
This validation's output is:
testParam1: 1
testParam2: 2
testParam4: 4
TOP BLOGS & COLUMNS
Open source Java projects: Storm
Dustin Marx
DUSTIN MARX
ObjectStreamClass: Peeking at a Java Object's Serialization
HttpClient basic authentication
Jeff Friesen
JEFF FRIESEN
Object-oriented language basics: Interfaces and multiple
ALL JAVAWORLD BLOGS »
The attribute testParam3 is not validated because we marked its getter as optional. All other attributes are validated and the result of the validation is okay. Now we want to set one of the attributes to null so that we can check if the validator will detect this error. Just comment out the line:
param.setTestParam2( new Integer( 2 ) );
After we restart, we receive the following output:
MORE LIKE THIS
NEWS
Simple classes for JDBC
HOW-TO
Java Tip 98: Reflect on the Visitor design pattern
NEWS
End-to-end internationalization of Web applications
testParam1: 1
Error: testParam2 in TestParameter is null!!!
testParam4: 4
Now we can see that the validator has detected the unset attribute.
What if the attribute is a kind of Collection?
If the attribute is a Collection, it's also checked if the Collection is null. But perhaps checking whether the Collection is null is not what you want. In most cases, you want to know whether the objects in Collection are null. If Collection's implementation does not allow null objects, you don't need to care about those null objects that don't extend AbstractParameter in the GenericClassAttributeValidator. The additional code for a Collection holding objects that extend the AbstractParameter looks like this:
if ( methodResult instanceof Collection )
{
Collection col = (Collection) methodResult;
Iterator iter = col.iterator( );
Object subParam = null;
while ( iter.hasNext( ) )
{
subParam = iter.next( );
if ( subParam instanceof AbstractParameter )
{
AbstractParameter abstractParam = ( AbstractParameter ) subParam;
abstractParam.validateWith( this );
}
}
}
All objects in the Collection that don't extend from the AbstractParameter class are not checked because we are going to use a Collection implementation that does not allow null objects. So the Collection implementation completes the check for us. If you decide to use an implementation that allows null objects, an additional null check is necessary for all other objects in the while loop:
else if( subParam == null )
{
System.out.println( "Error: SubParameter not set in Collection!" );
}
Dependencies between values
In some cases, an attribute is optional only if another attribute of the value object has an assigned value. The "optionality" of attribute sometimesOptional depends on the value of the attribute actionType. Maybe action holds values that stand for the actions: for example addSomething = 1, updateSomething = 2, and deleteSomthing = 3. If action's value is 1 or 3, the sometimesOptional attribute is not optional. If the action value equals 2, it is optional. We must set the optionality of sometimesOptional when we set the value for actionType:
public void setActionType(int actionType)
{
this.actionType = actionType;
super.clearOptionalMethods( );
switch( this.actionType )
{
case ActionParameter.ACTION_ADD :
super.addOptionalMethod( "getSometimesOptional4" );
super.addOptionalMethod( "getSometimesOptional5" );
break;
case ActionParameter.ACTION_UPDATE :
super.addOptionalMethod( "getSometimesOptional1" );
break;
case ActionParameter.ACTION_REMOVE :
super.addOptionalMethod( "getSometimesOptional1" );
super.addOptionalMethod( "getSometimesOptional2" );
super.addOptionalMethod( "getSometimesOptional3" );
break;
default :
break;
}
}
MORE LIKE THIS
NEWS
Simple classes for JDBC
HOW-TO
Java Tip 98: Reflect on the Visitor design pattern
NEWS
End-to-end internationalization of Web applications
You can see that it's necessary to clear the list of optional methods because if you set the actionType more than once, more and more methods will be added as optional methods. Another solution involves implementing an AddActionParameter, an UpdateActionParameter, and a RemoveActionParameter, which all extend the AbstractParameter class. Then you won't need the attribute actionType! But maybe the class with the actionType attribute exists and has been used often. So to refactor the class easily, you must use the switch statement.
Prospect
We can now think about extending AbstractParameter with more functionality—for example, range-validation. The AbstractParamter needs a datastructure to store the range values. A HashMap, which stores
a range object with the getter method-name as a key, could also work. Or you could check whether aString
value contains some defined words. And so on. Also think about Perl 5 regular expressions! All these checks could be implemented inValidator
classes, which implement theIClassAttributeValidator
interface. You also can subtype theGenericClassAttributeValidator
if you want to use attribute null checks and additional value checks.
In J2EE applications, value objects are often used to transfer the data of a business process from a client to the server. But if you check the attribute of this value object on the server only, you might have to cancel the business process because an erroneous attribute, which is not optional, is null. You must interrupt the business process and send an error back to the client. It is good practice to use these validators on the client side in your delegate and on the server side as well (maybe one business process calls another). Checking value objects on the client side avoids unnecessary calls to the server and reduces network traffic!
Copyright © 2011 - All Rights Reserved - Softron.in
Template by Softron Technology