Hibernate, hashCode, equals and Eclipse

Java programmers use often Eclipse to write their code, and it’s common to rely on the Eclipse features to quickly generate the hashCode() and equals(Object obj) methods of the beans.

Working on a Hibernate based application, I often noticed unexpected issues, and after some in depth debugging I’ve found that probably some of these problems were caused by the Eclipse automatic generation of equals method.

In my opinion, this is mostly caused by the fact that Hibernate generates on top of our entity bean classes other proxy classes that overrides the getters, and other methods in order to provide the lazy loading of data.

I.e.: When Hibernate loads from the DB a Movie bean, it will have, for example, an associated list of MovieActor objects. Obviously Hibernate will not fetch all the data related to every single actor, but anyway it will generate the stub for the MovieActor objects.

The programmer would be tempted to use code like this:

Movie aMovie = getEntityManager.find(...);
MovieActor aMovieActor = getEntityManager.find(...);
if (aMovie.getActors().contains(aMovieActor)) {
	System.out.println(aMovieActor.getActor().getName() + " acted in the movie " + aMovie.getTitle());
}

I noticed that contains method often returns false even if that actor really acted in that movie!
After some long debugging sessions, my final idea is that the problem is how Eclipse automatically generated the equals method of MovieActor class:

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (!(obj instanceof MovieActor))
			return false;
		MovieActor other = (MovieActor) obj;
		if (id == null) {
			if (other.id != null)
				return false;
		} else if (!id.equals(other.id))
			return false;
		return true;
	}

In this code id is an @EmbeddedId composed by the Actor and the Movie associations. What I believe that causes problems is: other.id!

This is because probably the Id of the other object hasn’t been loaded yet, and its fetching will happen on the calling of getId() of the proxy class built on MovieActor.

So, I changed the equals method this way:

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (!(obj instanceof MovieActor))
			return false;
		MovieActor other = (MovieActor) obj;
		if (id == null) {
			if (other.getId() != null)
				return false;
		} else if (!id.equals(other.getId()))
			return false;
		return true;
	}

And after this little change, contains began to work correctly!

Another very important thing is to check use ‘instanceof’ to compare types otherwise some ugly code would be generated.
Some checks like if (getClass() != obj.getClass()) would miserably fail when hibernate proxy classes are used.

Java EE Web Application with Eclipse Ganymede

First of all setup Eclipse Ganymede for Java EE and add to it a Tomcat6 server, as described in my previous tutorial.

Choose, from the File menu New, Dynamic Web Project in the option panel, give a name to the project (i.e. Struts2-Rest), choose a Target Runtime (that you should have already defined, in my case, Apache Tomcat v.6.0) and click Next.

New Dynamic Web Project

New Dynamic Web Project

Here you can define the web application context root, that’s the relative path where it will be accessibile, if you choose Struts2-Rest as context root, your application will be accessible on http://www.yourserver.com/Struts2-Rest or http://localhost:8080/Struts2-Rest if you use the default Tomcat configuration provided by Eclipse (with the Tomcat HTTP Connector on the port 8080)

The Content Directory parameters defines the directory inside your project where is located the “root” of the .war you’re going to generate, use the default WebContent directory.

And, obviously, Java Source Directory defines the directory where your Java sources will be stored. Just for your information, after compilation, the generated .class files are automatically moved by Eclipse into WebContent/WEB-INF/classes.

New Dynamic Web Project - Web Module

New Dynamic Web Project - Web Module

Just click finish. Your brand new project will appear in the Project Explorer

Project Explorer - New Web Project Created

Project Explorer - New Web Project Created

The Deployment Descriptor is obviously associated with the web.xml file. The Java Resources (src) contains your source code, and WebContent contains all the .jsp files, the static contents (images, css, javascripts) and the WEB-INF directory of your .war that will contain the compiled classes (in /WEB-INF/classes) and the libraries (in /WEB-INF/lib).

Setup Tomcat6 on Eclipse

Download Eclipse IDE for Java EE Developers from http://www.eclipse.org/downloads/ and tomcat6 from http://tomcat.apache.org/download-60.cgi

Extract both of them where you prefer. I extracted Eclipse in /opt/eclipse and Tomcat in /opt/tomcat6), then run Eclipse.

When you’ll run eclipse it asks you about creating a new workspace (that will be used to store all of your projects), so create a workspace, usually somewhere in your user home directory.

When Eclipse is up and running, choose preferences from the window menu. Choose from the bar on the left: Server, Runtime Environments.

Preferences window in Eclipse

Preferences

Click the button Add, choose Apache Tomcat 6.

New Server Runtime Environment

New Server Runtime Environment

In the next page, browse on your disk and choose the directory where you previously extracted Tomcat. In my case it’s /opt/tomcat6. Finally click Finish.

New Server Runtime Environment - Server Path

New Server Runtime Environment - Server Path

Well, until now we have just told to our workspace where Tomcat “installation” is located on our disk.

But, if we wish to run Java Web Applications within Eclipse, we should setup a Server and eventually assign to it a specific configuration.
Go in the Servers view, right click and choose New, then Server.

Select “Tomcat v6.0 Server” as server type (or probably it will be automatically pre-selected), then, in the Server Runtime environment select box you’ll have to choose “Apache Tomcat v6.0” (that’s probably the only available option.

New Tomcat Server in Eclipse

New Tomcat Server in Eclipse

Click on Next, Eclipse will prompt you to eventually add (or remove) web projects from this Server, in this case, if your workspace is empty you’ll have not any project to add. So, click Finish.

eclipse-add-remove-projects-from-tomcat

Add remove Eclipse projects from Tomcat

In the Servers panel, you will see the Tomcat you just added, and in the Project Explorer view, a new Server configuration will magical appear.

So you can edit the configuration file server.xml as you prefer, change AJP or HTTP connector ports and so on, start/stop/debug the server and obviously add and remove projects from it.

Editing Tomcat configuration in Eclipse

Editing Tomcat configuration in Eclipse

It is also possible to add other server “instances”, just right click again in the “Servers” view, and follow the procedure described before.

In this way, you will just a single “Tomcat” binaries location (that you defined in the first step of this tutorial), but you’ll have the chance to add many instances of that server, each of them with its specific configuration (imagine the /conf directory of Tomcat) and its specific web application (imagine the /webapps directory).

Multiple Tomcat Instances in Eclipse

Multiple Tomcat Instances in Eclipse

For the more expert ones, it is similar to have more instances on the same tomcat binaries defined on different CATALINA_BASE paths.

I hope this tutorial has been useful, please post any question or comment.