I am trying to represent a bidirectional relationship with some entities using the @IdClass
annotation as is shown in this answer: https://stackoverflow.com/a/32920550/8977519
I have a solution setup that follows the linked answer exactly and the application runs fine. I am able to use all of my CRUD end points and the changes are reflected in the DB. However, when I try to execute my tests the springTestContextPrepareTestInstance
step fails.
Composite Id Class
@Getter
@Setter
@EqualsAndHashCode
public class CompositeId implements Serializable {
private static final long serialVersionUID = ...;
@Type(type = "uuid-char")
private UUID entity1;
@Type(type = "uuid-char")
private UUID entity2;
}
Bidirectional Entity Class
@Entity
@Table(name = "bidirectional_entity")
@NoArgsConstructor
@Getter
@Setter
@IdClass(CompositeId.class)
public class BidirectionalEntity {
@Id
@ManyToOne
@JoinColumn(name = "entity1_id", referencedColumnName = "id")
private Entity1 entity1;
@Id
@ManyToOne
@JoinColumn(name = "entity2_id", referencedColumnName = "id")
private Entity2 entity2;
...
}
Entity Classes
@Entity
@Table(name = "entity1")
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@ToString
public class Entity1 {
@Id
@GenericGenerator(name = "uuid2", strategy = "uuid2")
@GeneratedValue(generator = "uuid2")
@Column(name = "id", updatable = false)
@Type(type = "uuid-char")
private UUID id;
@OneToMany(mappedBy = "entity1", orphanRemoval=true, cascade = CascadeType.ALL)
@Setter(AccessLevel.NONE)
private List<BidirectionalEntity> entities = new ArrayList<>();
...
}
@Entity
@Table(name = "entity2")
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@ToString
public class Entity2 {
@Id
@GenericGenerator(name = "uuid2", strategy = "uuid2")
@GeneratedValue(generator = "uuid2")
@Column(name = "id", updatable = false)
@Type(type = "uuid-char")
private UUID id;
@OneToMany(mappedBy = "entity2", orphanRemoval=true, cascade = CascadeType.ALL)
@Setter(AccessLevel.NONE)
private List<BidirectionalEntity> entities = new ArrayList<>();
...
}
The error given is:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: {CompositeId Class} has no persistent id property
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1778)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:593)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1105)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:316)
at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:127)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:99)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:117)
at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:108)
at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:190)
at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:132)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:246)
at org.springframework.test.context.testng.AbstractTestNGSpringContextTests.springTestContextPrepareTestInstance(AbstractTestNGSpringContextTests.java:145)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:124)
at org.testng.internal.MethodInvocationHelper.invokeMethodConsideringTimeout(MethodInvocationHelper.java:59)
at org.testng.internal.Invoker.invokeConfigurationMethod(Invoker.java:458)
at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:222)
at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:142)
at org.testng.internal.TestMethodWorker.invokeBeforeClassMethods(TestMethodWorker.java:168)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:105)
at org.testng.TestRunner.privateRun(TestRunner.java:648)
at org.testng.TestRunner.run(TestRunner.java:505)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:455)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:450)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:415)
at org.testng.SuiteRunner.run(SuiteRunner.java:364)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:84)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1208)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1137)
at org.testng.TestNG.runSuites(TestNG.java:1049)
at org.testng.TestNG.run(TestNG.java:1017)
at org.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:73)
at org.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:123)
Caused by: org.hibernate.AnnotationException: {CompositeId Class} has no persistent id property
at org.hibernate.cfg.AnnotationBinder.bindIdClass(AnnotationBinder.java:2858)
at org.hibernate.cfg.AnnotationBinder.mapAsIdClass(AnnotationBinder.java:1053)
at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:781)
at org.hibernate.boot.model.source.internal.annotations.AnnotationMetadataSourceProcessorImpl.processEntityHierarchies(AnnotationMetadataSourceProcessorImpl.java:250)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess$1.processEntityHierarchies(MetadataBuildingProcess.java:231)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:274)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:904)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:935)
at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:57)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:390)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:377)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:341)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1837)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1774)
... 45 more
Update
After doing some novice debugging, in the Hibernate Core (5.3.9) AnnotationBinder
class -> bindIdClass
method the componentId
object properties
list is empty when performing setup for test(obviously, it's what is checked to throw the error). However, when running the program normally, there are two properties of value
org.hibernate.mapping.SimpleValue([org.hibernate.mapping.Column(entity*_id)])
with name
entity*. Matching up with the BidirectionalEntity
class as it should be.