Summary Question: Do different instances of a sub-class inherit the same parent class instance?
I would have thought that two instances of a sub-class also have different parent class instances, but perhaps I am not understanding something about inheritance. Hopefully someone can explain why I am seeing this behavior.
Here is the class where I see the "problem":
@Entity
@Table(name="inventory.parts_fstnr_capscrews")
public class FastenerCapScrew implements PartInterface {
...
private Dimension length;
private Dimension threadLength;
...
@ManyToOne
@JoinColumn(name="fk_lengthid")
@JsonView(View.CommodityPartPOView.class)
public Dimension getLength() {
return length;
}
public void setLength(Dimension length) {
this.length = length;
}
@ManyToOne
@JoinColumn(name="fk_threadlengthid")
@JsonView(View.CommodityPartPOView.class)
public Dimension getThreadLength() {
return threadLength;
}
public void setThreadLength(Dimension threadLength) {
this.threadLength = threadLength;
}
@Override
@Transient
public List<FiltersInterface> getFilters() {
List<FiltersInterface> filters = new ArrayList<>();
LOGGER.debug(filters.toString());
LOGGER.debug(length.toString());
LOGGER.debug(threadLength.toString());
if (length!=null) {
length.setDbColumnName("FK_LengthID");
filters.add(length);
}
LOGGER.debug(filters.toString());
LOGGER.debug(length.toString());
LOGGER.debug(threadLength.toString());
if (threadLength!=null) {
threadLength.setDbColumnName("FK_ThreadLengthID");
filters.add(threadLength);
}
LOGGER.debug(filters.toString());
LOGGER.debug(length.toString());
LOGGER.debug(threadLength.toString());
return filters;
}
}
And here is the Dimension class:
@Entity
@Table(name="utilities.dimensions")
public class Dimension extends FiltersExtension implements FiltersDimensionInterface {
...
}
And the extended class:
public class FiltersExtension {
protected String dbColumnName;
public String getDbColumnName() {
return dbColumnName;
}
public void setDbColumnName(String dbColumnName) {
this.dbColumnName = dbColumnName;
}
}
When I call the getFilters() method in FastenersCapScrew, the initial output for length and threadLength is as expected, and both have dbColumnName=null. Then it runs length.setDbColumnName("FK_LengthID");, but both length and threadLength are changed and both show dbColumnName=FK_LengthID. Then it runs threadLength.setDbColumnName("FK_ThreadLengthID");, and again both items are changed so that dbColumnName=FK_ThreadLengthID.
Initially, I thought it must have something to do with the hashCode and equals methods in Dimension, so I changed them to include dbColumnName as below:
@Override
public int hashCode() {
LOGGER.debug("First compare hashCode with dbColumnName="+this.dbColumnName);
int hash = 3;
hash = 37 * hash + this.dimID;
hash = 37 * hash + Objects.hashCode(this.dbColumnName);
return hash;
}
@Override
public boolean equals(Object obj) {
LOGGER.debug("Now compare equals with dbColumnName="+this.dbColumnName);
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Dimension other = (Dimension) obj;
if (this.dimID != other.dimID) {
return false;
}
LOGGER.debug("Now compare the column name: "+this.dbColumnName+" vs. "+other.dbColumnName);
if (!Objects.equals(this.dbColumnName,other.dbColumnName)) {
return false;
}
return true;
}
Can anyone explain to me why changing one Dimension instance changes the other one as well? And what would be the way to fix this so that I do have two totally separate instances? Thanks!
For what it is worth, I am using Java 8 and Spring Boot 2.0.3 with Hibernate, but I don't think that has any bearing on this problem.
Dimensionobjects, i.e. how are you callingsetLength()andsetThreadLength()?Dimensionobjects are initialized as part of the Spring Data JPA / Hibernate. So, for a givenFastenerCapScrewdatabase record, it finds the correspondingDimensiondatabase records and builds the objects.