Using Spring and Hibernate With JPA And Entity Interfaces

I’m currently setting up a new Hibernate project and finally getting around to trying out JPA annotations instead of using any Hibernate configuration or mapping files– what the hell took me so long!!??! Anyhow, among the many gotchas I came across, one was how to deal with using Interfaces with Hibernate entity beans and associations.

When you declare an association to a Hibernate Entity with an Interface without using the correct annotation syntax to point Hibernate at the implementing class, you will likely see exceptions like this while running JUnit 4 tests in Eclipse:

CODE:
  1. java.lang.IllegalStateException: Failed to load ApplicationContext
  2.     at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:201)
  3.     at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:109)
  4.     at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75)
  5.     at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:255)
  6.     at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:111)
  7.     at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.invokeTestMethod(SpringJUnit4ClassRunner.java:148)
  8.     at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:51)
  9.     at org.junit.internal.runners.JUnit4ClassRunner$1.run(JUnit4ClassRunner.java:44)
  10.     at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:27)
  11.     at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:37)
  12.     at org.junit.internal.runners.JUnit4ClassRunner.run(JUnit4ClassRunner.java:42)
  13.     at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:97)
  14.     at org.junit.internal.runners.CompositeRunner.runChildren(CompositeRunner.java:33)
  15.     at org.junit.runners.Suite.access$000(Suite.java:26)
  16.     at org.junit.runners.Suite$1.run(Suite.java:93)
  17.     at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:27)
  18.     at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:37)
  19.     at org.junit.runners.Suite.run(Suite.java:91)
  20.     at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:38)
  21.     at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
  22.     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
  23.     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
  24.     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
  25.     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
  26. Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘geoSessionFactory’ defined in class path resource [com/peerdigital/spring/applicationContext.xml]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: @OneToOne or @ManyToOne on com.peerdigital.geolocation.model.DefaultCountryEntityImpl.regionEntity references an unknown entity: com.peerdigital.geolocation.model.DefaultRegionEntityImpl
  27.     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1338)
  28.     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:473)
  29.     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409)
  30.     at java.security.AccessController.doPrivileged(Native Method)
  31.     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:380)
  32.     at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:264)
  33.     at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
  34.     at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:261)
  35.     at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185)
  36.     at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164)
  37.     at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:423)
  38.     at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:728)
  39.     at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:380)
  40.     at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:84)
  41.     at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:42)
  42.     at org.springframework.test.context.TestContext.loadApplicationContext(TestContext.java:173)
  43.     at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:197)
  44.     … 23 more
  45. Caused by: org.hibernate.AnnotationException: @OneToOne or @ManyToOne on com.peerdigital.geolocation.model.DefaultCountryEntityImpl.regionEntity references an unknown entity: com.peerdigital.geolocation.model.DefaultRegionEntityImpl
  46.     at org.hibernate.cfg.ToOneFkSecondPass.doSecondPass(ToOneFkSecondPass.java:81)
  47.     at org.hibernate.cfg.AnnotationConfiguration.processEndOfQueue(AnnotationConfiguration.java:456)
  48.     at org.hibernate.cfg.AnnotationConfiguration.processFkSecondPassInOrder(AnnotationConfiguration.java:438)
  49.     at org.hibernate.cfg.AnnotationConfiguration.secondPassCompile(AnnotationConfiguration.java:309)
  50.     at org.hibernate.cfg.Configuration.buildMappings(Configuration.java:1148)
  51.     at org.springframework.orm.hibernate3.LocalSessionFactoryBean.buildSessionFactory(LocalSessionFactoryBean.java:673)
  52.     at org.springframework.orm.hibernate3.AbstractSessionFactoryBean.afterPropertiesSet(AbstractSessionFactoryBean.java:211)
  53.     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1369)
  54.     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1335)
  55.     … 39 more

Most of the solutions I saw made you create a duplicate persistence.xml that had all of the same information in it which seemed silly to me. Eventually with the help of Google I came across the answer somewhere (which I no longer have around) which was to modify the field annotation to point at the class which implements the Interface:

CODE:
  1. @ManyToOne(targetEntity = DefaultRegionEntityImpl.class)
  2. @JoinColumn(name = “region_code_fk”, referencedColumnName = “region_code_pk”, insertable = false, updatable = false)
  3. private RegionEntity regionEntity;

One other thing to check– make sure your @Entity annotation is importing the JPA annotation (javax.persistence.Entity), and NOT the Hibernate annotation (org.hibernate.annotations.Entity). If you import the Hibernate @Entity annotation it will not find the entity bean.

Hopefully that’s of some help to someone. Just a quick post– back to work I go!

This entry was posted in Frameworks, Languages and tagged , , , , , . Bookmark the permalink.

2 Responses to "Using Spring and Hibernate With JPA And Entity Interfaces"

Leave a reply