.remove() and .contains() not working on your Java set?

If you suddenly experience problems callling set.remove() and set.contains() on your Java Set instances, you might be using Hibernate, which replaces your Set instance with its own version (PersistentSet), which uses a HashSet internally to store your data.

For example, the problem I faced was the following:

Person.java

public class Person(){

 String _name;

 public Person(String name){
  _name = name;
 }

 @Override
 public String toString(){
  return _name;
 }

 @Override
 public int hashCode(){
  if (_name != null) return _name.hashCode();
  return -1;
 }
}

MyTestApplication.java

public class MyTestApplication{

 public static void main(String[] args){

  Person steve = new Person("Steve");
  Set persons = new Set();
  persons.add(steve);
  System.out.println(persons);

  boolean contains = persons.contains(steve);
  System.out.println(String.valueOf(contains));

  persons.remove(steve);
  System.out.println(persons);

  for (Person person : persons){
   System.out.println("Contains: " + person.toString());
  }

 }
}

The code above prints the following to the console:

[Steve]
false
[Steve]
Contains: Steve

This definitely was not expected.

The reason: If you call set.remove(obj) or set.contains(obj), the internal HashSet will automatically call obj.hashCode() and use the returned value to search for obj.
Normally, this works without any issues, but there is one case where it doesn’t and that’s when:

  • You use Hibernate
  • You load the Set data eagerly
  • You override the obj.hashCode() method

The reason for this is a bug in Hibernate.

For me, a solution was to not override the obj.hashCode() method.
Since this is not a solution for all cases, I recommend to follow the link above and read through the comments. There are quite some workarounds described there. I’m sure one of them will work for you.

Good luck, soldier.

(God, Hibernate! I officially hate you now. It took me a whole day to find the reason for this issue).

Correct naming convention for boolean values in Hibernate mapping files

Ok, this just took me a while to figure out so I thought I’d share it here.

If you have a boolean variable that follows the naming convention “isValue” (e.g. boolean isPerson = false;), then the according mapping file property name may not include the “is” part of the name, for example:

<property name="person" column="is_person" />

Otherwise, Hibernate throws some weird Exceptions.
In my case it was:

Initial SessionFactory creation failed.org.hibernate.InstantiationException: could not instantiate test object FOO
Caused by org.hibernate.InstantiationException: could not instantiate test object BAR
Caused by: java.lang.reflect.InvocationTargetException
Caused by: java.lang.NoClassDefFoundError: Could not initialize class BAR

Hint: Inside your Java class, the following conventions must be used for getter and setters:

public boolean isPerson();
public void setPerson();

Don’t use:
public void setIsPerson();
!!!

Quickfix: Hibernate integration for ZK applications

If you’re using the awesome ZK framework together with Hibernate you might run into some issues where Hibernate behaves a little funky while the application runs.

The trouble’s cause

According to the developers of ZK, the reason for this is ZK’s multi-threaded event model. Whenever an event gets fired, a new event thread is created. This will lead to multiple instances of the Hibernate session class (one per thread) and thus lead to unpredictable behavior.

The quick fix

If you don’t want to read the whole blah-blah in the linked article, here is the quick fix. Just insert the following lines into your zk.xml file and you should be fine:

<!-- Hibernate SessionFactory life cycle -->
<listener>
<description>Hibernate SessionFactory life cycle</description>
<listener-class>org.zkoss.zkplus.hibernate.HibernateSessionFactoryListener</listener-class>
</listener>

<!-- Hibernate OpenSessionInView life cycle -->
<listener>
<description>Hibernate Open Session In View life cycle</description>
<listener-class>org.zkoss.zkplus.hibernate.OpenSessionInViewListener</listener-class>
</listener>