3

So I started using Spring Data JPA, I find it very easy to use at first especially with simple POJO entities, I managed to perform simple CRUD operations with a single entity (Person), but as I dig deeper with my design(inheritance), I'm starting to have a hard time dealing with Spring JPA repositories when it comes to inheritance design.

Legend :

POJOs

Repositories

Sample class that uses those two above

Exceptions thrown

xml configuration

Person class (base, abstract class)

 @MappedSuperclass
 public abstract class Person {
       ..properties, getters and setters with hibernate annotations
}

Student class (child, extends Person)

 @Entity
 @Table(name = "STUDENT")
 public class Student extends Person {
        .. properties, getters and setters SPECIFIC for a student
 }

REPOSITORIES

PersonRepository (base, parent repository)

 public interface PersonRepository<T extends Person, ID extends Serializable> extends JpaRepository<T, ID> {
 }    

StudentRepository (child, extends PersonRepository)

 public interface StudentRepository extends PersonRepository<Student, Integer>{
 }

Sample class

 @Service ("manager")
  public class Manager {

  @SuppressWarnings("rawtypes")
  @Resource (name = "personRepository")
  private PersonRepository personRepository;

  @SuppressWarnings("unchecked")
  public void savePerson(Person p) {

      personRepository.save(p);
  }
}

Exceptions thrown

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'manager': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'personRepository': FactoryBean threw exception on object creation; nested exception is java.lang.NullPointerException at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:308) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1185) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:703) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482) at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:139) at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:83) at edu.main.Main.main(Main.java:12) Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'personRepository': FactoryBean threw exception on object creation; nested exception is java.lang.NullPointerException at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:175) at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:103) at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1512) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:313) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:198) at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.autowireResource(CommonAnnotationBeanPostProcessor.java:446) at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.getResource(CommonAnnotationBeanPostProcessor.java:420) at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor$ResourceElement.getResourceToInject(CommonAnnotationBeanPostProcessor.java:545) at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:155) at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87) at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:305) ... 13 more Caused by: java.lang.NullPointerException at java.lang.Class.isAssignableFrom(Native Method) at org.springframework.data.jpa.repository.support.JpaEntityInformationSupport.getMetadata(JpaEntityInformationSupport.java:58) at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getEntityInformation(JpaRepositoryFactory.java:145) at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:83) at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:66) at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:146) at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.getObject(RepositoryFactoryBeanSupport.java:120) at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.getObject(RepositoryFactoryBeanSupport.java:39) at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:168)

xml Configuration

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:repository="http://www.springframework.org/schema/data/repository"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:tx="http://www.springframework.org/schema/tx"             xmlns:context="http://www.springframework.org/schema/context"
 xsi:schemaLocation="http://www.springframework.org/schema/beans 
     http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
     http://www.springframework.org/schema/context  
     http://www.springframework.org/schema/context/spring-context-4.0.xsd
     http://www.springframework.org/schema/tx 
     http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
     http://www.springframework.org/schema/data/repository
     http://www.springframework.org/schema/data/repository/spring-repository.xsd
     http://www.springframework.org/schema/data/jpa 
     http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">


<context:annotation-config />
<context:component-scan base-package="edu.service" />
<jpa:repositories base-package="edu.repository" />
<tx:annotation-driven />

<context:property-placeholder
    location="classpath:properties/database.properties"
    ignore-unresolvable="false" />

<bean id="dataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="${jdbc.driverClassName}" />
    <property name="url" value="${jdbc.url}" />
    <property name="username" value="${jdbc.username}" />
    <property name="password" value="${jdbc.password}" />
</bean>

<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="packagesToScan">
        <list>
            <value>edu.domain</value>
        </list>
    </property>
    <property name="persistenceUnitName" value="personPU"/>
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
    </property>
    <property name="jpaProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
            <prop key="hibernate.show_sql">false</prop>
        </props>
    </property>
</bean>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

I'm trying to to find a specific words to search for a similar problem, but no luck, what could be the problem that causes my repository to not have a repository bean(a NullPointerException/BeanCreationException)?. And another thing I want to add, and am I doing something wrong with my design pattern? should I reflect my POJOs inheritance pattern to my Repositories? I'm trying to make my PersonRepository perform operations on my POJO/Entites that are children of the Person class(abstract parent), thats why I came up with the idea of repository inheritance. My specific goal is, Persist/Perform CRUD on any objects that extends the Person using PersonRepository. Any help/suggestion/comments is greatly appreciated. Please. Thank you so much

Jeff
  • 519
  • 1
  • 10
  • 18
  • Try parameterizing your service class. I suspect Spring understands that your superinterface is generic and is having trouble with the raw type. – chrylis -cautiouslyoptimistic- Aug 23 '14 at 07:12
  • 1
    Not directly related, but you may find [this post](http://stackoverflow.com/a/25241995/2587435) interesting – Paul Samsotha Aug 23 '14 at 07:23
  • thanks for the link, yes it does not look like directly related, but I'm pretty sure, somewhere along the road, I might encounter something where I need to apply the things implied on that post, thank you so much! – Jeff Aug 23 '14 at 08:52

1 Answers1

1

I believe the PersonRepository should be annotated with @NoRepositoryBean.

In my application I've done it this way:

Parent:

@NoRepositoryBean
public interface UserRepository<T> extends JpaRepository<T, Long> {
}

Child:

@Repository
public interface EmployeeRepository extends UserRepository<Employee> {
}

Hope it helps.

Vaelyr
  • 2,841
  • 2
  • 21
  • 34
  • 1
    That's only if you *don't* want Spring Data to create a ``UserRepository``, but that's what Jeff wants. – Emerson Farrugia Aug 23 '14 at 07:01
  • Wait, what's the point in that? It just makes the code look ugly. – Vaelyr Aug 23 '14 at 07:05
  • Current NullPointException problem is that he defines PersonRepository which has generic parameters, but doesn't specify any in the declaration, instead hides rawtypes. That's just wrong. – Vaelyr Aug 23 '14 at 07:11
  • Great! its working now, thank you so much!! but do you think this is a good practice?? Pardon me, but English is not my mother tounge.. my code does look ugly with this kind of design? – Jeff Aug 23 '14 at 07:19
  • Well, I actually don't see a real reason why you would need an abstract or a parent repository unless you have some really specific queries you need to describe which will be used from child repositories, for simple CRUD there is no need for that kind of an abstraction. To reduce any kind of duplication this is certainly a good idea. – Vaelyr Aug 23 '14 at 11:40