Search code examples
javajpaeclipselink

Combining @Embeddable with @MappedSuperclass in one entity in JPA (EclipseLink)


After switching to EclipseLink 2.6.0 (from 2.5.2), for a domain class declared with

@MappedSuperclass
@Embeddable
public class ADomainClass { ... }

I get an error:

Caused by: Exception [EclipseLink-28018] (Eclipse Persistence Services - 2.6.0.v20150309-bf26070): org.eclipse.persistence.exceptions.EntityManagerSetupException
Exception Description: Predeployment of PersistenceUnit [default] failed.
Internal Exception: java.lang.ClassCastException: org.eclipse.persistence.internal.jpa.metamodel.EmbeddableTypeImpl cannot be cast to org.eclipse.persistence.internal.jpa.metamodel.MappedSuperclassTypeImpl
    at org.eclipse.persistence.exceptions.EntityManagerSetupException.predeployFailed(EntityManagerSetupException.java:231)
    ... 73 more
Caused by: java.lang.ClassCastException: org.eclipse.persistence.internal.jpa.metamodel.EmbeddableTypeImpl cannot be cast to org.eclipse.persistence.internal.jpa.metamodel.MappedSuperclassTypeImpl
    at org.eclipse.persistence.internal.jpa.metamodel.MetamodelImpl.preInitialize(MetamodelImpl.java:398)
    at org.eclipse.persistence.internal.jpa.metamodel.MetamodelImpl.<init>(MetamodelImpl.java:113)
    at org.eclipse.persistence.internal.jpa.metamodel.MetamodelImpl.<init>(MetamodelImpl.java:132)
    at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.preInitializeMetamodel(EntityManagerSetupImpl.java:3755)
    at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.predeploy(EntityManagerSetupImpl.java:2000)
    ... 71 more

Is it possible this is an unwanted regression in this new version of EclipseLink?

(Note that when I look at the ClassCastException I can see in the same stack frame, it is caused by my class ADomainClass.)

EDIT:

My use case is an inheritance between Embeddables.
My superclass ADomainClass (which is @Embeddable) and is extended by another @Embeddable class ASubtype does not work, unless the superclass is annotated with @MappedSuperclass.

According to http://en.wikibooks.org/wiki/Java_Persistence/Embeddables#Inheritance, EclipseLink / Toplink supports this JPA non-standard feature. Though one should achieve it with DescriptorCustomizer and the InheritancePolicy. (And not with @MappedSuperclass?)


Solution

  • I agree with @Chris's comment, I'm not sure how it ever worked for you, or what would be the purpose of such class. @MappedSuperclass and @Embeddable serve a completely different purpose.

    @MappedSuperclass is used to group some common properties used by all entities, like id, or some auditing information like createdAt and createdBy. From JPA 2.1 spec:

    [2.11.2] Typically, the purpose of such a mapped superclass is to define state and mapping information that is common to multiple entity classes.

    In short, mapped superclasses are to be extended by entities. Entities can also extend non-entity classes, but in that case the superclass isn't persisted, only behavior is inherited. Also, all annotations on such classes are ignored.

    [2.11.3] The non-entity superclass serves for inheritance of behavior only. The state of a non-entity superclass is not persistent. Any state inherited from non-entity superclasses is non-persistent in an inheriting entity class. This non-persistent state is not managed by the entity manager[23]. Any annotations on such superclasses are ignored.

    @Embeddable is used to group/embed some properties of an entity in a separate class, which can also be reused in other entities. All the fields of embeddable class are mapped to columns in the owning entity, except if @ElementCollection and @CollectionTable are used for storing them. The JPA specification does not define inheritance for embeddables (though EclipseLink supports it by use of its native API) EclipseLink Doc. They can also contain mappings to other entities (from JPA 2.0). Nevertheless, they are not intended to be extended by entities. From wiki

    Generally attempting to mix inheritance between embeddables and entities is not a good idea, but may work in some cases.
    ...
    Relationships to embeddable objects from entities other than the embeddable's parent are typically not a good idea, as an embeddable is a private dependent part of its parent. Generally relationships should be to the embeddable's parent, not the embeddable. Otherwise, it would normally be a good idea to make the embeddable an independent entity with its own table.