I am currently defining JPA entities for a legacy database (lots of composite keys, but also single-column keys). I have created the following entity superclass:
@MappedSuperclass
public abstract class AbstractEntity<ID extends Serializable> {
public abstract ID getId();
public abstract void setId(ID id);
}
And then a superclass for composite keys (as well as a superclass for long primary key, not listed here):
@MappedSuperclass
public abstract class AbstractEmbeddedIdEntity<ID extends Serializable> extends AbstractEntity<ID> {
@EmbeddedId
private ID id;
public AbstractEmbeddedIdEntity() {
id = newId();
}
@Override
public ID getId() {
return id;
}
@Override
public void setId(ID id) {
this.id = id;
}
protected abstract ID newId();
}
And finally concrete entities like this:
@Entity
@Table(name = "firstEntity")
public class FirstEntity extends AbstractEmbeddedIdEntity<FirstEntityId> {
public FirstEntity() {
}
@Embeddable
public static class FirstEntityId implements Serializable {
@Column(name = "firstId")
private String firstId;
public FirstEntityId() {
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof FirstEntityId)) {
return false;
}
FirstEntityId other = (FirstEntityId) obj;
return
Objects.equals(firstId, other.firstId);
}
@Override
public int hashCode() {
return Objects.hash(firstId);
}
}
@Override
protected FirstEntityId newId() {
return new FirstEntityId();
}
}
Now the issue is that if I have multiple entities like this and try to access an ID property of an entity (currently with Spring Boot, e.g. findByIdFirstId(String firstId)), an exception is thrown:
java.lang.IllegalArgumentException: Unable to locate Attribute with the the given name [firstId] on this ManagedType [unknown]
I have debugged this and found out that in hibernate, the metamodel maps all of my entities to the same MappedSupperclass instance. During application startup, the @EmbeddedId returned by newId() is set to the MappedSupperclass, overwriting the ID of the previous entity. So in the end, all entities are mapped to the same MappedSupperclass, but the MappedSupperclass only has the @EmbeddedId of the last entity.
In the above example, accessing the ID property fails because the @EmbeddedId of the last entity doesn't have a property called "firstId" (it has been overwritten with the ID properties of the last entity).
Now I am wondering if my approach is wrong, if I am missing something or if this could be an issue with hibernate?
Complete example using spring boot available on github. Run with mvn spring-boot:run.
@MappedSuperclassis used for inheritance, and therefore imply a huge link between your different classes extending it. You should probably map them one by one, in the simplest way, so they're not related by yourAbstractEntityclass.