Showing posts with label generic. Show all posts
Showing posts with label generic. Show all posts

Sunday, December 9, 2007

Generic equal and toString

When writing unit tests in many cases it's required to implement toString to display the DTO (Data Transfer Object) in the log file or in the console for debugging.

In this case a good solution is to use generic DTO implementaion which implement "toString" method in a generic way using reflection, The method pass on all the getters methods recusivly and print the fields values, If a new field is added or removed the toString code doesn't need to be change.

In the same way it can be also used to implement generic "equals" method which compare each two getters of two objects recusevly.

This implementaion is also suitable for tests and I don't recommened to use that where performance issues are important since it use reflection.

Here is the implementation code

/**
* Generic DTO class

* Implements a functionality such as toString(), equals() , etc.
*/
public abstract class GenericDTO implements Serializable
{

private static final Logger logger = Logger.getInstance();

/**
* A String representation of all the get methods.
*
* @return A String concatenations toString of the returned values of all the get methods.

* The get methods do not have parameters
*/
public String toString()
{
Method[] methods = this.getClass().getMethods();
StringBuffer result = new StringBuffer();
boolean comma = false;
try
{
int length = methods.length;
result.append("[");
for (int i = 0; i < length; i++)
{
String methodName = methods[i].getName();
if (methodName.startsWith("get") && !methodName.startsWith("getClass"))
{
if (comma)
{
result.append(", ");
}
else
{
comma = true;
}

Object o = methods[i].invoke(this, null);
result.append(methodName.substring(3)); //after the get
result.append("():");
if (o==null)
{
result.append("null");
}
else
{
result.append(o.toString());
}
}

}
result.append("]");
}
catch (IllegalArgumentException e)
{
logger.error("toString()", e);
}
catch (IllegalAccessException e)
{
logger.error("toString()", e);
}
catch (InvocationTargetException e)
{
logger.error("toString()", e);
}
return result.toString();
}

/**
* Indicates whether some other object is "equal to" this one

* An AbstractDTO is equal to another if and only if it is the same class and have

* the same values of the get methods.
*
* @return true if it the same class and the returned values of the get methods are equal
* false otherwise
*/
public boolean equals(Object obj)
{
if (this == obj)
{
return true;
}
boolean result = false;
try
{
if (obj.getClass() == this.getClass())
{
result = true;
Method[] objMethods = obj.getClass().getMethods();
int methodsLength = objMethods.length;

int i = 0;
while (i < methodsLength && result)
{
String methodName = objMethods[i].getName();
if (methodName.startsWith("get"))
{
// invoke on my object
Object objReturnedObject = objMethods[i].invoke(this, null);
// invoke on the parameter object
Object myReturnedObject = objMethods[i].invoke(obj, null);

if (objReturnedObject==null)
{
if (myReturnedObject!=null)
{
result = false;
}
}
else
{
if (!objReturnedObject.equals(myReturnedObject))
{
result = false;
}
}
}
i++;
}
}
}
catch (IllegalArgumentException e)
{
logger.error("equals()", e);
return false;
}
catch (IllegalAccessException e)
{
logger.error("equals()", e);
return false;
}
catch (InvocationTargetException e)
{
logger.error("equals()", e);
return false;
}

return result;
}

}

Links

 
RSS Feeds Submission Directory