How to lose a Java object in a Collection (Set)

I was a little careless the other day, I lost one of my business objects in a Collection!

Or to be more precise a Java business object that I had placed in a Set could only be found by iterating through the contents of the Set, if I asked the contains(Object) method to find the object that I just added but it couldn't find it. Now the clue that I should have spotted sooner was that the rather plain add(Object) method I was calling was in fact on another application class and not directly on the Set.

What was happening was this other add(Object) was adding the object to the Set and then was adding the Set into the business object (it was doing this correctly as we wanted a parent-child relationship so that each knew about the other). The problem was that the hashCode method of the business object used it's reference to the Set to compute it's value.

When the object was added to the Set hashCode produced one value, once the Set was linked to the object, hashCode produced a different value. Because contains uses the object's hashCode to try and find the object in the Set it couldn't find it.

Swapping the order of events, i.e. link the Set first then add it to the parent Set ensured that the hashCode value was consistent and now the object could always be found.

So the moral of this story: be very careful when writing hashCode & equals methods and make sure you stop messing with the object the moment you add it to the Collection.

Technorati Tags: , , , ,

ClassNotFoundException when running JUnit unit tests within Eclipse (using Maven)

I've been using Eclipse & Maven for a while now and have the m2eclipse plugin installed so that Eclipse understands the Maven dependencies. I've never had any problems running unit tests within Eclipse until recently after I update the plugin. To see if you have this problem open any unit test within Eclipse and then run it as a JUnit test (or just CTRL-F11). It is fails with a 'ClassNotFoundException ' then you have this problem.

After obtaining the classpath that Eclipse was using to spawn off the unit test it was clear that Maven (or more correctly the Maven m2eclipse plugin) was the root of the issue. It intercepts the fork operation so that it can correctly build the classpath with all the appropriate dependencies, the only thing that was missing on the classpath was any reference to the project's Java class files!

The Maven project in question has the Java source and unit test classes in sub-modules and the Maven plugin wasn't adding these sub-modules to the classpath.

Note: Back up your .project and .classpath files before you perform the steps below.

After much web searching to no avail and then much headscratching I finally found the solution tucked away in the project's Maven settings. Right-click on the project in the left-hand pane and choose 'Properties' then click 'Maven' and you should be presented with the screen below:

Tick the 'Include Modules' box, click 'Apply', agree to Maven possibly trashing your project and wait...

You should now be able to run your unit tests again as it's put all the classes within the sub-modules encapsulated by the top-level POM on the classpath. I think this option must have changed from version 0.9.4 onwards of the m2eclispe plugin as my previous version 0.9.3 didn't suffer with this issue.

Technorati Tags: , , , , , , ,