Thursday, January 22, 2009

Simplest way to override hashCode(), equals(Object) and toString()

We all know that these three methods belongs to java.lang.Object, the parent of all other Java classes, and they are intended to be overridden by subclasses wherever appropriate.

Both hashCode and equals(Object) should be overridden for entity objects that have a database identity and value objects that are used to pass parameters and return result, especially if they are used in a Set or a Map.

An often overlooked benefit of overriding these two methods for value objects is that it makes assertion and verification of invocation on mock objects much easier and more resilient to changes.

As for stateless objects, such as web actions, service objects, entity managers, repositories and data access objects, there is little to gain by overriding these methods.

With regards to toString, it would make our life debugging or reading log file a lot easier if it is overridden even though business may not mandate this.

In "Effective Java", Joshua Bloch provides the following guidance on when it is appropriate to override these methods:
  • Override equals(Object) unless:
    • Each instance of the class is inherently unique.
    • You don't care whether the class provides a "logical equality" test.
    • A superclass has already overridden equals, and the superclass behaviour is appropriate for this class.
    • The class is private or package-private, and you are certain that its equals method will never be invoked.
  • (Item 9) Always override hashCode when you override equals
  • (Item 10) Always override toString

But, why are we not overriding these methods as often as we should? I can think of the following reasons:
  • When we write a new class, our focus is on the implementation of the core responsibility of the class. Overriding these methods are often a result of after thoughts.
  • We can "cheat" in unit testing by substituting "logical equality" test with a "uniqueness" test, especially if the value object is immutable so that the class under test does not need to defensively copy an incoming value object to preserve invariants.
  • As there is a fair bit of code in overriding equals(Object), it requires unit testing the correctness of the overriding, which can be several times longer than the overriding method itself, depending on how thorough your tests are.
  • These methods are considered "affordable debt" in order to meet a project deadline.

Is there a way to override these methods with least effort?

Yes. We'll go through several ways of overriding these methods to find the simplest way.

DIY
When hand-crafting equals method, make sure you follow the high-quality equals method recipe from "Effective Java":
  1. Use the == operator to check if the argument is a reference to this object.
  2. Use the instanceof operator to check if the argument has the correct type.
  3. Cast the argument to the correct type.
  4. For each "significant" field in the class, check if that field of the argument matches the corresponding field of this object.
    • Avoid the possibility of a NullPointerException if some instance fields are nullable.
  5. When you are finished writing your equals method, ask yourself three questions: Is it symmetric? Is it transitive? Is it consistent?

Some additional suggestions:
  • If the superclass also overrides equals method, invoke super.equals(obj) as well, provided that the superclass's overriding method does not use a getClass test in place of the instanceof test.
  • Unit test symmetry, transitivity and consistency.

Pros
  • No third-party dependencies

Cons
  • Humans are error-prone, so it definitely requires unit-testing
  • Can be time-consuming
  • Requires "maintenance" when adding new instance fields
  • equals(Object and hashCode() can get out-of-sync when introducing new instance fields

Code generation by IDE
In IDEA, select "Code" -> "Generate..." and select "equals() and hashCode()".

In Eclipse, select "Source" -> "Generate equals() and hashCode()...".

Both IDEs let you choose whether to use instanceof test or not, and which instance fields are used in these methods.

Pros
  • No third-party dependencies

Cons
  • Requires re-generation when adding new instance fields
  • Unit testing may be needed if the generated code is significantly "enhanced by hand"
  • equals(Object and hashCode() can get out-of-sync when introducing new instance fields without regenerating the code

Typical Use of Apache Commons Lang's Builders
The "typical use" of EqualsBuilder, as documented, is as follows:

public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof MyClass == false) {
return false;
}
MyClass rhs = (MyClass) obj;
return new EqualsBuilder()
.appendSuper(super.equals(obj))
.append(field1, rhs.field1)
.append(field2, rhs.field2)
.append(field3, rhs.field3)
.isEquals();
}


Pros
  • Flexible

Cons
  • Lengthy
  • May require some degree of unit testing, usually the reflexive test, null test and type test.
  • Requires "maintenance" when adding new instance fields
  • equals(Object and hashCode() can get out-of-sync when introducing new instance fields
  • Third-party library dependency (this should not be an issue as Apache Commons Lang in ubiquitous...)

The Simplest Way to Override these methods
The possibly simplest way is to use the reflection-based methods of the Apache Commons Lang's Builders, as shown below:

@Override
public int hashCode()
{
return HashCodeBuilder.reflectionHashCode(this);
// or
// return HashCodeBuilder.reflectionHashCode(23, 13, this);
}

@Override
public boolean equals(Object obj)
{
return EqualsBuilder.reflectionEquals(this, obj);
// or, if transient fields are tested while some other fields should be excluded, and the reflection should be done
// up to a certain class (there are many overloading versions, so choose the right one)
// return EqualsBuilder.reflectionEquals(this, obj, true, Parent.class, new String[]{"excludedField1", "excludedField2"});
}

@Override
public String toString()
{
return ToStringBuilder.reflectionToString(this);
// or, if you'd like to choose a different style
// return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
}


Pros:
  • No "maintenance" when adding new instance fields.
  • Won't accidentally make hashCode() and equals(Object) out-of-sync when introducing new instance fields
  • No need to write unit tests for these methods because they are too simple to break.

Cons:
  • The overhead of reflection. But you shouldn't avoid these methods simply because of the overhead:
    • Unless your class is used in big Collections and as key in big Maps, the overhead should be insignificant.
    • Don't prematurely optimize. Wait until you identify this is where the bottleneck is using a profiler before you try a different implementation. In that case, don't forget to add unit tests first.
  • Does not apply to entity objects directly. For these objects with a database identity, the equality test should be based only on database key, preferrably unique natural key.

So, if you think this is good, then why don't you put it in the code templates?

Embed in Code Templates

If you use IDEA, go to "Settings" -> "File Templates", select "Templates" tab and edit the content of "Class" to the following:

#if (${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

#parse("File Header.java")

public class ${NAME}
{

@SuppressWarnings("unused")
private static final Log log = LogFactory.getLog(${NAME}.class);

@Override
public int hashCode()
{
return HashCodeBuilder.reflectionHashCode(this);
}

@Override
public boolean equals(Object obj)
{
return EqualsBuilder.reflectionEquals(this, obj);
}

@Override
public String toString()
{
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
}

}


If you use Eclipse, select "Preferences", under "Java" -> "Code Style" -> "Code Templates", expand "Code".

Edit "New Java files" to something like the following:

${filecomment}
${package_declaration}

import org.apache.commons.lang.builder.EqualsBuilder;

import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

${typecomment}
${type_declaration}


Then edit "Class body" and change to the following:


@SuppressWarnings("unused")
private static final Log log = LogFactory.getLog(${type_name}.class);

@Override
public int hashCode()
{
return HashCodeBuilder.reflectionHashCode(this);
}

@Override
public boolean equals(Object obj)
{
return EqualsBuilder.reflectionEquals(this, obj);
}

@Override
public String toString()
{
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
}


Finally, if you use JAXB 2.x to generate Java classes from XML Schema, make sure you use jaxb2-commons's jakarta-commons-lang plugin to generate these methods. I have painful memory of working with plain JAB2-generated classes in unit testing before I discovered this precious plugin, which inspired me to write this post entry to share the simplest way to override hasCode(), equals(Object) and toString() methods with you....

Monday, December 29, 2008

Preventing NullPointerException

When a NullPointerException (NPE) is thrown, it can be hard to trace back to the bug that causes it, especially if it comes from an instance variable of a mutable class, where the execution of buggy code may have finished long before the NPE is thrown. With the wide adoption of the best practice of immutability and IoC container, it is not seen as frequently as before and most of the time it is easy to locate the bug, such as a missing setter injection in the Spring application context. Probably as a result, recently some developers seem to have relaxed on null checking as I have seem some codes in an open soure project that completely lacks both null checking and documentation of the preconditions on methods.

This week, I have seen two good practices (IMHO) of null checking and related documentation:

The first is a static method named T checkNotNull(T reference, String referenceName) in class Preconditions I found in the Activity Stream project. This class is modelled after a similar class from Google Collections API. Note that it does not share any of its source code.

This reminds me of the static methods void notNull(Object object) and void notNull(Object object, String message) from Validate class in Apache Commons Lang that are used a lot in my previous job for null checking:

import static org.apache.commons.lang.Validate.notNull;
...
public class Foo
{
private final Bar bar;

public Foo(Bar bar)
{
notNull(bar, "Bar must not be null.");
this.bar = bar;
...
}
...
}

The T checkNotNull(T reference, String referenceName) has the advantage of returning the parameter, thus it can be assigned right after the null checking:

import static com.atlassian.streams.util.Preconditions.checkNotNull;
...
public class Foo
{
private final Bar bar;

public Foo(Bar bar)
{
this.bar = checkNotNull(bar, "Bar");
...
}
...
}

Similar to null checking, quite often there is also a need to guard against empty String, blank String (containing only whitespaces, see StringUtils), empty Collection, null-containing Collection (containing a null element), empty Array, null-containing Array and empty Map, etc.

Luckily, Validate provides most of these checks:
  • void notEmpty(Collection collection, String referenceName)
  • void noNullElements(Collection collection, String referenceName)
  • void notEmpty(String string, String referenceName)
  • void notEmpty(Object[] array, String referenceName)
  • void noNullElements(Object[] array, String referenceName)
  • void notEmpty(Map map, String referenceName)

Unfortunately, they all return void and cannot be chained, and it can force you to write your own little static method to do all the checks, or use it before the proper check:

import static org.apache.commons.lang.Validate.*;
...
public class Foo extends Bar
{
public Foo(List list)
{
super(notEmptyNoNullElements(list));
}

private static notEmptyNoNullElements(Collection collection)
{
notEmpty(collection);
noNullElements(collection);
}
...
}

So I have added the following methods to Preconditions:
  • <T, C extends Collection<T>> C notEmpty(C collection, String name)
  • <T, C extends Collection<T>> C noNullElements(C collection, String name)
  • <T, C extends Collection<T>> C notEmptyNoNullElements(C collection, String name)
  • <T> T[] notEmpty(T[] array, String name)
  • <T> T[] noNullElements(T[] array, String name)
  • <T> T[] notEmptyNoNullElements(T[] array, String name)
  • <K, V> Map<K, V> notEmpty(Map<K, V> map, String name)
  • String notBlank(String text, String name)

The other example is actually in the Google Gadgets API. All the optional parameters are prefixed with "opt_", making it very obvious. So instead of just documenting in javadoc, we can also given a more intention-revealing name to parameters, such as:

/**
* Do something.
* @param bar Used to do something. Cannot be <code>null</code>. Mandatory...
* @param baz Used to do something. Can be <code>null</code>. Optional...
*/
public void foo(Bar bar, Baz optBaz)
{
...
}

Finally, Preconditions probably should not sit in streams-core. It would be more useful if it is moved to some core projects, such as atlassian-core, so that different teams do not have to reinvent the wheel.

Wednesday, July 23, 2008

Unable to install equinox p2 plugins for Eclipse Ganymede

I have been trying to install "build utility feature for equinox p2 plugins", on which Spring IDE Eclipse plugin and M2Eclipse plugin have a dependency. But I'm constantly getting an "Invalid zip file format" error:

An error occurred while collecting items to be installed
Error closing the output stream for master-equinox-p2/org.eclipse.update.feature/1.0.0.v20080506-4--8Mc44yANsYbyiqu-z-uDo0 on repository file:/C:/eclipse-3.4-ganymede/.
Error unzipping C:\DOCUME~1\Alex\LOCALS~1\Temp\master-equinox-p2_1.0.0.v20080506-4--8Mc44yANsYbyiqu-z-uDo044914.jar: Invalid zip file format


It seems to be unable to download a good copy of master-equinox-p2 JAR file. I have cleaned up all the temporary internet files and tried to install on a different machine but still no luck. I suspect that the mirror site is corrupted, probably with a bad signature or something. But it doesn't seem to allow me to choose mirror site in Ganymede any more. Urrghh!

Saturday, June 14, 2008

Which is the hottest Java web framework that people want to learn?

A recent post on The "Break it Down" Blog, Which is the Hottest Java Web Framework? Or Maybe Not Java? has attracted lots of attention, including that of Java Web Frameworks Guru Matt Raible.

The author excluded Tapestry and Stripes because of the high noise from the common usage of these terms.

Some readers, including myself, commented that the high search rate may reflect that some frameworks, like JSF, especially JSF 1.1, are so bad that people encounter problems all the time and have to rely on Google to search for solutions.

In order to find out how people really like to learn about those frameworks mentioned in the post, I tweaked the search terms a bit by adding the word "tutorial", as I reckon anyone who wants to learn a web technology is likely to search for a tutorial on that technology, only if they speak English...

And here are the result.

Comparing JSF, Struts 2, Spring MVC / Spring Webflow, JBoss Seam and Apache Wicket:

As we can see, JSF is much more popular than all other Java web frameworks and is very popular in India, Hong Kong, Czech, Singapore and the Philippines. Struts 2 ranked second, slightly better than Spring MVC and Seam. And Wicket didn't even have enough search volume to rank.

Then I compared Struts 2, Spring MVC / Spring Webflow, JBoss Seam, Tapestry and Grails:

Basically, there is little search volume for tutorials on Grails, Tapestry and Stripes (not shown in this image). This is probably an indication that the official website for these frameworks have good documentation and tutorials, where JSF is only a specification and you have to find tutorials elsewhere.

Here the interesting observation is: Struts 2 is very popular in India and Brazil; Seam is far more popular in Austria, Spring MVC is especially popular in London and Grails has been taken up quite well in Germany. And surprsingly, even Australia has more search volumes for these frameworks than the United States.

Finally, I compared Ruby on Rails, Adobe Flex, JSF, Struts 2 and Spring MVC / Spring Webflow:



Hmmm, Ruby on Rails, Adobe Flex and JSF are popular to the same level. However, the popularity of JSF has been on a plateau for the past few years and has begun to decline. Ruby on Rails also starts to show signs of decline, while Flex is rising sharply.

And Ruby on Rails are very popular in San Francisco and San Jose, CA, the Philippines and Sweden. And Flex is rather popular in Brazil and Europe.

Saturday, March 8, 2008

More on How to make Acegi work on Sun Application Server 8.x?

Applying the solution mentioned in my previous post IMHO: How to make Acegi work on Sun Application Server 8.x? has been proved working quite well. Well, until I encountered the same ClassCastException again. This time it was because the access was denied. Looking into the stack trace, I found that it was because Acegi's AccessDeniedHandlerImpl forwards the SecurityContextHolderAwareRequestWrapper to show the error page.

Similar to the solution in the previous post, I creates a NullPrincipalAccessDeniedHandlerImpl, which extends Acegi's AccessDeniedHandlerImpl but wrap the HttpServletRequest with the NullPrincipalHttpServletRequestWrapper.

Following is the source code of NullPrincipalAccessDeniedHandlerImpl:

package au.net.ozgwei.util.spring.security;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.acegisecurity.AccessDeniedException;
import org.acegisecurity.ui.AccessDeniedHandlerImpl;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import au.net.ozgwei.util.httpservlet.NullPrincipalHttpServletRequestWrapper;

/**
* An Acegi AccessDeniedHandler implementation designed specific to get around
* the bug in Sun Application Server 8.x where a custom security framework's
* implementation of Principal is casted to Sun Application Server's own
* implementation.
*
* @author Alex
* @version 1.0
*/
public class NullPrincipalAccessDeniedHandlerImpl extends
AccessDeniedHandlerImpl {

@SuppressWarnings("unused")
private static final Log log =
LogFactory.getTrace(
NullPrincipalAccessDeniedHandlerImpl.class);

/**
* Default no-arg constructor.
*/
public NullPrincipalAccessDeniedHandlerImpl() {
super();
}

@Override
public void handle(ServletRequest aRequest, ServletResponse aResponse,
AccessDeniedException aAccessDeniedException) throws IOException,
ServletException {

super.handle(new NullPrincipalHttpServletRequestWrapper(
(HttpServletRequest)aRequest), aResponse, aAccessDeniedException);
}

}

Of course, the Spring application context must be changed to replace the original AccessDeniedHandler implementation with this in the definition of the exceptionTranslationFilter bean:
<bean id="exceptionTranslationFilter"
class="org.acegisecurity.ui.ExceptionTranslationFilter">
<property name="authenticationEntryPoint">
<ref local="authenticationProcessingFilterEntryPoint"/>
</property>

<property name="accessDeniedHandler">
<bean class="au.com.cardlink.common.util.spring.security.NullPrincipalAccessDeniedHandlerImpl">
<property name="errorPage" value="/faces/ForbiddenAccess.jsp"/>
</bean>
</property>

</bean>

Now it works even if user's access to a protected URL is denied by Acegi.

Friday, February 22, 2008

12 Technologies I Would Like to Grasp in 2008

  1. Grails
  2. Groovy
  3. OSGi
  4. Spring Batch
  5. Spring Security 2.0
  6. Spring Web Services
  7. AspectJ
  8. JBoss Seam
  9. RichFaces
  10. Mule
  11. JavaFX
  12. Selenium

Wednesday, February 6, 2008

Grails 1.0 is Out!

Grails 1.0 was finally released yesterday!
To quote from the official website: "The Search Is Over!"
After a long and exciting wait, Grails, the response to Ruby on Rails (RoR) from the Java land, has reached maturity.
It adopts "Convention over Configuration" (CoC), which has been made popular by RoR.
It's built on top of solid frameworks, such as Spring, Hibernate & Sitemesh, allowing developers to quickly develop web application with a focus on CRUD operations on database.
It also has a healthy plugin system to allow contributors to develope plugins, such as Acegi plugin.
When developing with Grails, you program in Groovy, a powerful scripting language that runs seamlessly on the JVM. It has all the powers that Ruby has and maybe more.
Enjoy the journey to Grails! I'm sure I will.