CRITICAL
Rule Definition
It's almost never correct to override equals() on a persistant subclass and include properties that do not belong to the persistent base class in the comparison. It's tricky to satisfy the requirements that equality be both symmetric and transitive in this case; and, more important, the business key wouldn't correspond to any well-defined candidate natural key in the database (subclass properties may be mapped to a different table).
Remediation
Reconsider your business key attributes and use only attributes from the base class.
Violation Code Sample
----> Java files:
public class Animal {
private Long id;
private String name;
...
public Long getId() {
return this.id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
...
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Animal)) return false;
final Animal animal = (Animal) o;
if (! (this.getName() == animal.getName()) ) return false;
return true;
}
}
public class Dog extends Animal {
private String race;
...
public String getRace() {
return this.race;
}
public String setRace(String race) {
this.race = race;
}
public boolean equals(Object o) { // VIOLATION
if (this == o) return true;
if (!(o instanceof Dog)) return false;
final Dog dog = (Dog) o;
if (! (this.getName() == dog.getName())) return false;
if (! (this.getRace() == dog.getRace())) return false;
return true;
}
}
public class Cat extends Animal {
private String color;
...
public String getColor() {
return this.color;
}
public String setColor(String color) {
this.color = color;
}
public boolean equals(Object o) { // VIOLATION
if (this == o) return true;
if (!(o instanceof Cat)) return false;
final Cat cat = (Cat) o;
if (! (this.getName() == cat.getName())) return false;
if (! (this.getColor() == cat.getColor())) return false;
return true;
}
}
----> animal.hbm.xml
<class name="Animal" table="animal">
<id name="id" type="long" column="animal_id">
<generator class="native"/>
</id>
<discriminator column="type" type="string"/>
<property name="name" column="name"/>
...
<subclass name="Dog" discriminator-value="DOG">
<property name="race" column="race"/>
...
</subclass>
<subclass name="Cat" discriminator-value="CAT">
<property name="color" column="color"/>
...
</subclass>
</class>
Fixed Code Sample
Remove the equals() method from Cat and Dog. If necessary, race and color attributes must be moved to the Animal class and be used into the equals() method. They will become a part of the business key.
Reference
Hibernate in Action (ISBN 1932394-15-X) p 125
Related Technologies
JEE
Technical Criterion
Programming Practices - Unexpected Behavior
About CAST Appmarq
CAST Appmarq is by far the biggest repository of data about real IT systems. It's built on thousands of analyzed applications, made of 35 different technologies, by over 300 business organizations across major verticals. It provides IT Leaders with factual key analytics to let them know if their applications are on track.