I have three tables:
CREATE TABLE PostAddresses
(
contact_id INTEGER NOT NULL,
ordinal_nbr SMALLINT NOT NULL,
PRIMARY KEY (contact_id, ordinal_nbr)
);
CREATE TABLE Foos
(
contact_id INTEGER NOT NULL,
ordinal_nbr SMALLINT NOT NULL,
PRIMARY KEY (contact_id, ordinal_nbr),
FOREIGN KEY (contact_id, ordinal_nbr) REFERENCES PostAddresses (contact_id, ordinal_nbr)
);
CREATE TABLE Bars
(
contact_id INTEGER NOT NULL,
ordinal_nbr SMALLINT NOT NULL,
numba INTEGER NOT NULL,
PRIMARY KEY (contact_id, ordinal_nbr, numba),
FOREIGN KEY (contact_id, ordinal_nbr) REFERENCES Foos (contact_id, ordinal_nbr)
);
Simple logic: Bars -> Foos -> PostAddresses all by (contact_id, ordinal_nbr), whatever it means.
Here the six entity and respective composite key classes.
@Entity
@Table(name = "PostAddresses")
public class PostAddress implements Serializable
{
@EmbeddedId
private PostAddressId embeddedId;
...
}
@Embeddable
public class PostAddressId implements Serializable
{
@Column(name = "contact_id")
private Integer contactId;
@Column(name = "ordinal_nbr")
private Integer ordinalNbr = 1;
...
}
@Entity
@Table(name = "Foos")
public class Foo implements Serializable
{
@EmbeddedId
private FooId embeddedId;
@MapsId(value = "postAddressId")
@OneToOne
@JoinColumns(value = {@JoinColumn(name = "contact_id", referencedColumnName = "contact_id"), @JoinColumn(name = "ordinal_nbr", referencedColumnName = "ordinal_nbr")})
private PostAddress postAddress = null;
...
}
@Embeddable
public class FooId implements Serializable
{
@Embedded
private PostAddressId postAddressId; //just one field!
...
}
@Entity
@Table(name = "Bars")
public class Bar implements Serializable
{
@EmbeddedId
private BarId embeddedId;
...
}
@Embeddable
public class BarId implements Serializable
{
@Embedded
private FooId fooId;
@Column(name = "numba")
private Integer numba;
...
}
It's really nothing special, Bar references Foo, Foo references PostAddress, all via composite key class. Since the foreign keys are composite and part of the PK, I must nest the ID classes into the ID classes. I thought this is correct. However, I get the following stack traces with Hibernate 3.6 and EclipseLink 2.2.0
Hibernate:
org.hibernate.AssertionFailure: Unexpected nested component on the referenced entity when mapping a @MapsId: tld.transmuc.model.Foo
at org.hibernate.cfg.CopyIdentifierComponentSecondPass.doSecondPass(CopyIdentifierComponentSecondPass.java:101)
at org.hibernate.cfg.Configuration.processSecondPassesOfType(Configuration.java:1424)
at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1388)
at org.hibernate.cfg.Configuration.buildMappings(Configuration.java:1345)
at org.hibernate.ejb.Ejb3Configuration.buildMappings(Ejb3Configuration.java:1477)
at org.hibernate.ejb.EventListenerConfigurator.configure(EventListenerConfigurator.java:193)
at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:1096)
at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:278)
at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:362)
at org.hibernate.ejb.HibernatePersistence.createEntityManagerFactory(HibernatePersistence.java:56)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:48)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:32)
at tld.transmuc.Main.main(Main.java:27)
Exception in thread "main" javax.persistence.PersistenceException: [PersistenceUnit: transmuc] Unable to configure EntityManagerFactory
at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:374)
at org.hibernate.ejb.HibernatePersistence.createEntityManagerFactory(HibernatePersistence.java:56)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:48)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:32)
at tld.transmuc.Main.main(Main.java:27)
Caused by: org.hibernate.AssertionFailure: Unexpected nested component on the referenced entity when mapping a @MapsId: tld.transmuc.model.Foo
at org.hibernate.cfg.CopyIdentifierComponentSecondPass.doSecondPass(CopyIdentifierComponentSecondPass.java:101)
at org.hibernate.cfg.Configuration.processSecondPassesOfType(Configuration.java:1424)
at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1388)
at org.hibernate.cfg.Configuration.buildMappings(Configuration.java:1345)
at org.hibernate.ejb.Ejb3Configuration.buildMappings(Ejb3Configuration.java:1477)
at org.hibernate.ejb.EventListenerConfigurator.configure(EventListenerConfigurator.java:193)
at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:1096)
at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:278)
at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:362)
... 4 more
EclipseLink:
Exception in thread "main" Local Exception Stack:
Exception [EclipseLink-30005] (Eclipse Persistence Services - 2.2.0.v20101118-r8514): org.eclipse.persistence.exceptions.PersistenceUnitLoadingException
Exception Description: An exception was thrown while searching for persistence archives with ClassLoader: sun.misc.Launcher$AppClassLoader@1f7182c1
Internal Exception: javax.persistence.PersistenceException: Exception [EclipseLink-28018] (Eclipse Persistence Services - 2.2.0.v20101118-r8514): org.eclipse.persistence.exceptions.EntityManagerSetupException
Exception Description: Predeployment of PersistenceUnit [transmuc] failed.
Internal Exception: java.lang.NullPointerException
at org.eclipse.persistence.exceptions.PersistenceUnitLoadingException.exceptionSearchingForPersistenceResources(PersistenceUnitLoadingException.java:126)
at org.eclipse.persistence.jpa.PersistenceProvider.createEntityManagerFactory(PersistenceProvider.java:136)
at org.eclipse.persistence.jpa.PersistenceProvider.createEntityManagerFactory(PersistenceProvider.java:65)
at javax.persistence.Persistence.createEntityManagerFactory(Unknown Source)
at javax.persistence.Persistence.createEntityManagerFactory(Unknown Source)
at tld.transmuc.Main.main(Main.java:27)
Caused by: javax.persistence.PersistenceException: Exception [EclipseLink-28018] (Eclipse Persistence Services - 2.2.0.v20101118-r8514): org.eclipse.persistence.exceptions.EntityManagerSetupException
Exception Description: Predeployment of PersistenceUnit [transmuc] failed.
Internal Exception: java.lang.NullPointerException
at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.predeploy(EntityManagerSetupImpl.java:1021)
at org.eclipse.persistence.internal.jpa.deployment.JPAInitializer.callPredeploy(JPAInitializer.java:95)
at org.eclipse.persistence.jpa.PersistenceProvider.createEntityManagerFactory(PersistenceProvider.java:127)
... 4 more
Caused by: Exception [EclipseLink-28018] (Eclipse Persistence Services - 2.2.0.v20101118-r8514): org.eclipse.persistence.exceptions.EntityManagerSetupException
Exception Description: Predeployment of PersistenceUnit [transmuc] failed.
Internal Exception: java.lang.NullPointerException
at org.eclipse.persistence.exceptions.EntityManagerSetupException.predeployFailed(EntityManagerSetupException.java:210)
... 7 more
Caused by: java.lang.NullPointerException
at org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.EmbeddedIdAccessor.process(EmbeddedIdAccessor.java:189)
at org.eclipse.persistence.internal.jpa.metadata.MetadataDescriptor.processMappingAccessors(MetadataDescriptor.java:1417)
at org.eclipse.persistence.internal.jpa.metadata.accessors.classes.ClassAccessor.processMappingAccessors(ClassAccessor.java:1405)
at org.eclipse.persistence.internal.jpa.metadata.accessors.classes.EntityAccessor.processMappingAccessors(EntityAccessor.java:1061)
at org.eclipse.persistence.internal.jpa.metadata.accessors.classes.EntityAccessor.process(EntityAccessor.java:601)
at org.eclipse.persistence.internal.jpa.metadata.MetadataProject.processStage2(MetadataProject.java:1464)
at org.eclipse.persistence.internal.jpa.metadata.MetadataProcessor.processORMMetadata(MetadataProcessor.java:483)
at org.eclipse.persistence.internal.jpa.deployment.PersistenceUnitProcessor.processORMetadata(PersistenceUnitProcessor.java:453)
at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.predeploy(EntityManagerSetupImpl.java:975)
... 6 more
EclipseLink gives me absolutely no hint as to which class is the offending one. At least Hibernate tells me about a problem with the @MapsId annotation and the Foo class:
org.hibernate.AssertionFailure: Unexpected nested component on the referenced entity when mapping a @MapsId: tld.transmuc.model.Foo
What's wrong here?
PS: I can put together an SSCCE, just ask if you need one (JavaSE, HSQLDB, Ant, Hibernate 3.6).
Simply removing the @Embedded annotation from within the EmbeddedId types that reference the dependant EmbeddedIds may resolve your issue.:
(EDIT): Another issue is the use of the FooId. This class should not be used. The ID class for Foo Enitity is the PostAddressId and the OneToOne "postAddress" should simply be marked @Id and not @MapsId. Likewise BarId should not have an Embedded defined but should directly reference the PostAddressId. The Bar Mapping that references PostAddress should use MapsId.
Please file a bug against EclipseLink for the terrible exception and if removing the @Embedded and the other updates in the edit does not resolve your issue please file an EclipseLink bug for that as well.