Archive for December, 2006

h1

Keep it Legible

December 7, 2006

As usual, Blaine got me thinking; this time about writing legible code, in particular around Jakarta Commons Collections. His take, and I whole-heartedly agree, is that you should first think about how client code has to use your object. Blaine’s initial problem revolved around the ugly code he needed to use Jakarta Collections, as in:

Collection activeAccounts = CollectionUtils
  .select(someAccounts, new Predicate() {
 public boolean evaluate(Object each) {
  return ((Accounteach).isActive();
 }
});

I initially liked his final solution,

// Account class
public static final Predicates BY = new Predicates();

// Class stuff...

static class Predicates {
 public Predicate active() {
  return new Predicate() {
   public boolean evaluate(Object each) {
    return ((Accounteach).isActive();
   }
  };
 }
}


// Client code
Collection activeAccounts = CollectionUtils
  .select(someAccounts, Account.BY.active());

but it eventually dawned on me that the CollectionUtils dependency leaks through to the client. The problem is easily solved with static methods on the Account Class:

public static Collection selectActive(Collection someAccounts) {
 return CollectionUtils
   .select(someAccounts, new Predicate() {
  public boolean evaluate(Object each) {
   return ((Accounteach).isActive();
  }
 });
}


// Client code
Collection active = Account.selectActive(someAccounts);

Even the word, static, makes me shudder but I couldn’t come up with a reason to prefer static inner classes static properties over static methods. I’ll compromise if it means I can hide more implementation from the client.

h1

When an Object in a Set is not in the Set

December 2, 2006

I have a Jukebox object with a Set of Song objects. I wrote a test to verify that the Songs were cascading properly when I updated and saved the Jukebox. Retrieving an empty Jukebox via Hibernate (Hibernate–keep that in mind), I added two Songs, saved the Jukebox, retrieved the Jukebox from the database and verified it had two Songs. So far, so good. Then I removed one of the Songs, saved the Jukebox, retrieved it again and my problems began. There were still had two Songs in the Jukebox. After some serious head scratching, I modified the test to look like this:

Song song = (Song) jukebox.getSongs().iterator().next();
assertTrue(jukebox.getSongs().contains(song));

Seems simple enough but the assertion failed. So the problem existed outside the persistence framework–or so I thought. After more digging, I (re)discovered that an object’s hashcode is used in an algorithm to determine whether a Set contains that particular object. The interesting thing to note is that the hashcode is run through “a ’supplemental hash function,’ which defends against poor quality hash functions”. The hashcode is actually modified before it’s used. As long as that “supplemental hash function” is also used for adding the object to the Set everything should be fine.

I suspect (and I have not yet investigated this) Hibernate does not implement (or implements differently) the “supplemental hash function” when adding an object to org.hibernate.collection.PersistentSet. If the object’s hash function is of poor quality, the modified hashcode used in the contains() method may not match the hashcode used when the object was added to the Set. The mismatched hashcodes then may prevent locating or removing the object.