5

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.

5
  • I think that it is better not to use any abstract classes when it comes to JPA/Hibernate mapping, unless it comes to superclasses, in the inheritance meaning of it. Indeed, @MappedSuperclass is 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 your AbstractEntity class. Commented Aug 29, 2017 at 8:18
  • What do you mean by 'all my entities point to the same instance for their MappedSupperclass'? There is no 'pointer to a common superclass object' in Java. Also, if I were you, I'd avoid using inner classes as embeddables Commented Aug 29, 2017 at 15:33
  • @crizzis: I have updated my question and fixed the incorrect part, thanks for pointing it out. Actually the hibernate metamodel maps all of my entities to the same MappedSupperclass instance. Also, why would you avoid using inner classes as embeddables? Commented Aug 30, 2017 at 8:58
  • 1
    Because the JPA spec states that 'entities must be top-level classes' as well as that 'Embeddables follow the same rules as entities', unless specified otherwise. Therefore, I would not rely on inner classes as embeddables being fully supported nor portable Commented Aug 30, 2017 at 9:23
  • Thanks! Wasn't aware of this. Commented Aug 30, 2017 at 9:27

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Bug also present in Spring Data JPA. Created Aug 2018. I moved back to Spring Boot 2.0.2 and it solved the issue for me. But i know this is unsafe to not have latest patches, I will try your workaround

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.