Boulevard of Broken Builds

Archive for October, 2007

EnhancerByCGLIB and equals()

by on Oct.16, 2007, under Uncategorized

Suppose you have a simple pojo class called MyPojo. Containing some arbitrary attributes and an id and version. The by IntelliJ generated equals() method for this object will look as follows.

    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass())
            return false;
        RecordImpl record = (RecordImpl) o;
        if (version != record.version) return false;
        if (id != null ? !id.equals(record.id) : record.id != null)
            return false;
        return true;
    }


Suppose now we use Hibernate to persist this object and there are two related object through which we retrieve two lazy instances of this object. The nature of Hibernate will now enforce both instances to be bytecode enhanced by cglib, which results in two instances of the class MyPojo$$EnhancerByCGLIB$$.
So what happens now if we call equals on those instances (let’s call them p1 and p2). So p1.equals(p2) results in the following execution lines.

  1. if (this == o) return true;
  2. Which is false, so we go on

  3. if (o == null || getClass() != o.getClass())
  4. Here we run into a problem. The class of o is MyPojo$$EnhancerByCGLIB$$ which does not equals the class of this, i.e.MyPojo. So what we need to do to fix this is to compare the class of p2 through different means

  5. if (o == null || !(o instanceof MyPojo))
  6. MyPojo pojo = (MyPojo) o;
  7. if (version != pojo.version) return false;
  8. Ouch. Hold on. Calling the version attribute will give an exception. Remember that the class is cglib enhanced. So the properties still have to be retrieved. We have to use the get method.

  9. if (version != pojo.getVersion()) return false;
  10. if (id != null ? !id.equals(pojo.id) : pojo.id != null)
  11. Again. We have to use the getter.

  12. if (id != null ? !id.equals(pojo.getId()) : pojo.getId() != null)
  13. return true;
  14. And finally we know they are equal.
    I wish this would be it. However, if MyPojo would have an interface in front of, the next problem comes around. CGLib will enhance the interface instead of the implementation. As a concequence the instance can no longer be casted to the implementing class. Hence, line 3 will give a ClassCastException. We have to adjust it to work with the interface. Fortunately we no longer use direct property access, so this won’t be a problem.

  15. MyPojo pojo = (MyPojo) o;

So now we have a equals which should evaluate correctly two instances. But I don’t like it. Making the equals method dependent on a implementing interface restricts me from implementing multiple interfaces. Or else I would have make the equals method more complex. If anyone has a better sollution, please let me know.

Leave a Comment more...

Looking for something?

Use the form below to search the site:

Still not finding what you're looking for? Drop a comment on a post or contact us so we can take care of it!

Visit our friends!

A few highly recommended friends...