Announcement Announcement Module
Collapse
No announcement yet.
Entity not found in JpaRepository when using generics Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Entity not found in JpaRepository when using generics

    Hi all,

    I have this problem using generics in combination with the JpaRespository. The examples underneath are simplyfied, but represent the essence of the issue.

    A lot of my domain objects must adhere to a specific interface, lets say the all must have a getName and setName method. Instead of creating a JpaRespository for each domainObject a like to use a repository based on Generics. But what ever I try invoking a method on the repository results in a "java.lang.IllegalArgumentException: Not an entity: interface nl.example.base.NamedObject".

    This problem still arises when I change the NamedObject interface into an abstract class, which is extended by the domain objects.
    Using the @MappedSuperclass or @Entity for the NamedObject abstract class gives the same result.

    I want every domain object persisted in it's own table (InheritanceType.TABLE_PER_CLASS,), so using discriminator columns is not aoption.

    How can I solve this problem?

    Thanks a lot,

    Frank

    ===========
    Interface
    ===========
    public interface NamedObject {
    String getName();
    void setName(String name);
    }
    =============
    Domain Object
    =============
    @Entity
    public class Person implements NamedObject {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Version
    private Integer version;

    @NotEmpty
    @Column(unique = true, nullable = false)
    private String name;

    public Long getId() {
    return id;
    }

    public void setId(Long id) {
    this.id = id;
    }

    public Integer getVersion() {
    return version;
    }

    public void setVersion(Integer version) {
    this.version = version;
    }

    @Override
    public String getName() {
    return name;
    }

    @Override
    public void setName(String name) {
    this.name = name;
    }
    }
    ==========
    Repository
    ==========
    public interface NamedObjectRepo<T extends NamedObject> extends JpaSpecificationExecutor<T>, JpaRepository<T, Long> {
    T findByName(String name);
    }


    =========
    TestCase
    =========
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = "classpath:/spring/appCtx*.xml")
    public class PersonRepoTest {
    @Autowired
    private NamedObjectRepo<Person> subject;

    @Test
    public void testSave() {
    String name = "pOne";
    Person personOne = new PersonFactory().setName(name).create();

    subject.save(personOne);
    }
    }
    =============
    Configuration
    =============
    ----------
    pom.xml
    ----------
    <dependency>
    <groupId>org.hibernate.javax.persistence</groupId>
    <artifactId>hibernate-jpa-2.0-api</artifactId>
    <version>1.0.1.Final</version>
    </dependency>
    <dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-entitymanager</artifactId>
    <version>3.6.7.Final</version>
    </dependency>
    <dependency>
    <groupId>org.hibernate.javax.persistence</groupId>
    <artifactId>hibernate-jpa-2.0-api</artifactId>
    <version>1.0.1.Final</version>
    </dependency>
    <dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-jpa</artifactId>
    <version>1.0.1.RELEASE</version>
    </dependency>
    <dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>3.6.7.Final</version>
    </dependency>
    ======
    Error
    ======
    java.lang.IllegalStateException: Failed to load ApplicationContext
    at org.springframework.test.context.TestContext.getAp plicationContext(TestContext.java:308)
    at org.springframework.test.context.support.Dependenc yInjectionTestExecutionListener.injectDependencies (DependencyInjectionTestExecutionListener.java:109 )
    at org.springframework.test.context.support.Dependenc yInjectionTestExecutionListener.prepareTestInstanc e(DependencyInjectionTestExecutionListener.java:75 )
    at org.springframework.test.context.TestContextManage r.prepareTestInstance(TestContextManager.java:321)
    at org.springframework.test.context.junit4.SpringJUni t4ClassRunner.createTest(SpringJUnit4ClassRunner.j ava:211)
    at org.springframework.test.context.junit4.SpringJUni t4ClassRunner$1.runReflectiveCall(SpringJUnit4Clas sRunner.java:287)
    at org.junit.internal.runners.model.ReflectiveCallabl e.run(ReflectiveCallable.java:15)
    at org.springframework.test.context.junit4.SpringJUni t4ClassRunner.methodBlock(SpringJUnit4ClassRunner. java:289)
    at org.springframework.test.context.junit4.SpringJUni t4ClassRunner.runChild(SpringJUnit4ClassRunner.jav a:231)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild( BlockJUnit4ClassRunner.java:47)
    at org.junit.runners.ParentRunner$3.run(ParentRunner. java:231)
    at org.junit.runners.ParentRunner$1.schedule(ParentRu nner.java:60)
    at org.junit.runners.ParentRunner.runChildren(ParentR unner.java:229)
    at org.junit.runners.ParentRunner.access$000(ParentRu nner.java:50)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRu nner.java:222)
    at org.springframework.test.context.junit4.statements .RunBeforeTestClassCallbacks.evaluate(RunBeforeTes tClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements .RunAfterTestClassCallbacks.evaluate(RunAfterTestC lassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.ja va:300)
    at org.springframework.test.context.junit4.SpringJUni t4ClassRunner.run(SpringJUnit4ClassRunner.java:174 )
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestR eference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecutio n.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRu nner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRu nner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRu nner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRu nner.main(RemoteTestRunner.java:197)
    Caused by: org.springframework.beans.factory.BeanCreationExce ption: Error creating bean with name 'namedObjectRepo': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalArgumentException: Not an entity: interface nl.example.base.NamedObject
    at org.springframework.beans.factory.support.FactoryB eanRegistrySupport.doGetObjectFromFactoryBean(Fact oryBeanRegistrySupport.java:149)
    at org.springframework.beans.factory.support.FactoryB eanRegistrySupport.getObjectFromFactoryBean(Factor yBeanRegistrySupport.java:102)
    at org.springframework.beans.factory.support.Abstract BeanFactory.getObjectForBeanInstance(AbstractBeanF actory.java:1440)
    at org.springframework.beans.factory.support.Abstract BeanFactory.doGetBean(AbstractBeanFactory.java:304 )
    at org.springframework.beans.factory.support.Abstract BeanFactory.getBean(AbstractBeanFactory.java:192)
    at org.springframework.beans.factory.support.DefaultL istableBeanFactory.preInstantiateSingletons(Defaul tListableBeanFactory.java:585)
    at org.springframework.context.support.AbstractApplic ationContext.finishBeanFactoryInitialization(Abstr actApplicationContext.java:895)
    at org.springframework.context.support.AbstractApplic ationContext.refresh(AbstractApplicationContext.ja va:425)
    at org.springframework.test.context.support.AbstractG enericContextLoader.loadContext(AbstractGenericCon textLoader.java:84)
    at org.springframework.test.context.support.AbstractG enericContextLoader.loadContext(AbstractGenericCon textLoader.java:1)
    at org.springframework.test.context.TestContext.loadA pplicationContext(TestContext.java:280)
    at org.springframework.test.context.TestContext.getAp plicationContext(TestContext.java:304)
    ... 24 more
    Caused by: java.lang.IllegalArgumentException: Not an entity: interface com.example.base.NamedObject
    at org.hibernate.ejb.metamodel.MetamodelImpl.entity(M etamodelImpl.java:160)
    at org.springframework.data.jpa.repository.support.Jp aMetamodelEntityInformation.<init>(JpaMetamodelEnt ityInformation.java:52)
    at org.springframework.data.jpa.repository.support.Jp aEntityInformationSupport.getMetadata(JpaEntityInf ormationSupport.java:61)
    at org.springframework.data.jpa.repository.support.Jp aRepositoryFactory.getEntityInformation(JpaReposit oryFactory.java:145)
    at org.springframework.data.jpa.repository.support.Jp aRepositoryFactory.getTargetRepository(JpaReposito ryFactory.java:83)
    at org.springframework.data.jpa.repository.support.Jp aRepositoryFactory.getTargetRepository(JpaReposito ryFactory.java:66)
    at org.springframework.data.repository.core.support.R epositoryFactorySupport.getRepository(RepositoryFa ctorySupport.java:146)
    at org.springframework.data.repository.core.support.R epositoryFactoryBeanSupport.getObject(RepositoryFa ctoryBeanSupport.java:120)
    at org.springframework.data.repository.core.support.R epositoryFactoryBeanSupport.getObject(RepositoryFa ctoryBeanSupport.java:39)
    at org.springframework.beans.factory.support.FactoryB eanRegistrySupport.doGetObjectFromFactoryBean(Fact oryBeanRegistrySupport.java:142)
    ... 35 more

  • #2
    You have to define a typed interface per top level @Entity or at least @MappedSuperclass. So in your case you should be fine by declaring an abstract class AbstractNamedEntity annotated with @MappedSuperclass containing the ID property e.g. and then alter the repo interfaces as follows:

    Code:
    @NoRepositoryBean
    public interface NamedObjectRepo<T extends NamedObject> extends JpaSpecificationExecutor<T>, JpaRepository<T, Long> {
      T findByName(String name);
    }
    
    public interface AbstractNamedObjectRepo extends NamedObjectRepo<AbstractNamedObject> {  }
    Then inject AbstractNamedObjectRepo into your client you can then persist and query all subtypes of AbstractNamedObject. This is due to the fact that Spring actually cannot inject generic types except Collections and Maps.

    PS: Please use [code] tags when posting code snippets

    Comment


    • #3
      Hello i also have the same kind of problem. but then i have interface for the Entity for API purpose.
      So in my effort to not tie anything like spring or jpa to my api i have interfaces entities in the let's say maven module core-api and have the actual class annotated with @Entity.

      Originally posted by Oliver Gierke View Post
      You have to define a typed interface per top level @Entity or at least @MappedSuperclass. So in your case you should be fine by declaring an abstract class AbstractNamedEntity annotated with @MappedSuperclass containing the ID property
      From what you said above regardless of the fact i would prefer not having jpa dependency in my api module, having the interfaces annotated with @MappeedSuperclass or moving @Entity from implementation POJO to the interface should have me going?


      Originally posted by Oliver Gierke View Post
      This is due to the fact that Spring actually cannot inject generic types except Collections and Maps.
      if this is true then i cannot properly have a decoupled api of my implementing module which uses spring.

      Please advice for how to get it fix or how best to avoid coupling to spring. THanks

      Comment

      Working...
      X