Tim
Tim

Reputation: 1695

Java equals implementation for two objects of the same class returns false when checking getClass()

I have implemented hashCode() and equals() for an object using the default from NetBeans:

@Override
public int hashCode() {
    int hash = 5;
    hash = 37 * hash + this.unitSystemID;
    return hash;
}

@Override
public boolean equals(Object obj) {
    if (this == obj) {
        return true;
    }
    if (obj == null) {
        return false;
    }
    LOGGER.debug(getClass().toString());
    LOGGER.debug(this.getClass().getClassLoader().toString());
    LOGGER.debug(obj.getClass().toString());
    LOGGER.debug(obj.getClass().getClassLoader().toString());
    if (getClass() != obj.getClass()) {
        return false;
    }
    final UnitSystem other = (UnitSystem) obj;
    if (this.unitSystemID != other.unitSystemID) {
        return false;
    }
    return true;
}

At the logging check-points, I get:

units.UnitSystem - class com.utilities.domain.units.UnitSystem

units.UnitSystem - org.springframework.boot.devtools.restart.classloader.RestartClassLoader@42d353e2

units.UnitSystem - class com.utilities.domain.units.UnitSystem_$$_jvst6b1_19ed

units.UnitSystem - org.springframework.boot.devtools.restart.classloader.RestartClassLoader@42d353e2

The equality fails at that point and equals returns false.

What is the extra _$$_jvst6b1_19ed? Where does it come from?

From what I understand, the classes should be equal if they are from the same class loader, which these are. I have not had a problem with this implementation anywhere else I have used it. Why is getClass() returning different things?

Upvotes: 1

Views: 233

Answers (2)

Andreas
Andreas

Reputation: 159135

Unless you actually subclass UnitSystem yourself, exact class matching isn't necessary, so replace

if (getClass() != obj.getClass()) {
    return false;
}

with

if (! (obj instanceof UnitSystem)) {
    return false;
}

You can't make UnitSystem class final since you want Hibernate to be able to create a subclass proxy, so you don't have absolute guarantee that UnitSystem won't be subclassed by non-Hibernate code, but is such an absolute guarantee really needed?

Upvotes: 3

Yuriy Tsarkov
Yuriy Tsarkov

Reputation: 2558

As @Andreas said in a comment it usually happens when the object has been fetched by a lazy loading. To get the initial object you should to unproxy it first. Here is an example of the unwrapper for a Hibernate

 @SuppressWarnings("unchecked")
  public static <T> T initializeAndUnproxy(T entity) {
    if (entity == null) {
      throw new InternalServerException("Entity passed for initialization is null");
    }

    T unproxy = entity;
    Hibernate.initialize(entity);
    if (isProxy(entity)) {
      unproxy = (T) ((HibernateProxy) entity).getHibernateLazyInitializer().getImplementation();
    }
    return unproxy;
  }

  public static <T> boolean isProxy(T entity) {
    return entity instanceof HibernateProxy;
  }

Upvotes: 0

Related Questions