简体   繁体   中英

JPA (Hibernate): Error when using @EmbeddedId in generic @MappedSuperclass

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, eg 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 .

This looks to me like a bug in hibernate, therefore I have created a ticket in the hibernate bug tracker . As a workaround I am now defining the ID attribute (@EmbeddedId) in the concreate entity classes instead of the abstract superclass.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM