web-dev-qa-db-fra.com

Spring Data JPA - échec de l'injection - BeanCreationException: impossible de câbler automatiquement le champ

j'ai suivi le tutoriel publié ici pour obtenir une application de base pour travailler avec Spring Data JPA. Maintenant, comment j'ai compris, en utilisant la configuration

<jpa:repositories base-package="my.package.to.scan" />

devrait aboutir à ce que le package soit analysé par Spring Data JPA pour les interfaces étendant JpaRepository et en crée un bean concreate afin qu'il puisse être utilisé n'importe où dans mes classes de service en utilisant le simple Spring @Autowired. Mais il échoue, disant qu'il ne peut pas trouver un bean avec className (qui est le nom par défaut que le bean obtient lors de sa création, en utilisant simplement le ClassName décapitalisé).

Cependant, quand je configure le bean manuellement dans mon applicationContext comme ceci:

<bean id="ClassName" class="my.package.to.scan.ClassName"/>

Le printemps est capable de trouver le haricot. Je reçois alors bien sûr une erreur car je veux créer un bean à partir d'une interface, ce qui ne peut évidemment pas fonctionner. MAIS le fait est qu'il semble que la "création automatique de bean" de Spring Data JPA semble échouer d'une manière ou d'une autre.

J'ai joint le code correspondant pour que vous puissiez le consulter. Btw, je dois mentionner que je développe un portlet, alors ne vous demandez pas pourquoi je n'ai pas de configuration de printemps. J'utilise actuellement un applicationConfig uniquement plus un MyPortlet-Portlet.xml pour les configurations de portlet (mais cela ne devrait pas être pertinent pour ce problème). J'ai ajouté les instructions d'importation juste pour m'assurer que je n'utilise pas les mauvaises annotations/classes.

applicationContext.xml

<beans *** ALL MY XMLN's and XSI's *** />
<context:annotation-config />
<jpa:repositories base-package="model.repositories" />

// JPA specific configuration here: dataSource, persistenceUnitManager exceptionTranslator, entityManagerFactory, SessionFactory, transactionManager - should not be relevant for this problem, tell me if i'm wrong

<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

ICustomerService - juste une interface pour le CustomerService

import model.entities.Customer;
public interface ICustomerService {
        // example method
    public Customer getCustomer(Long customerId);   
}

CustomerService - la classe utilisée par ma logique d'application pour obtenir/définir des données ORM

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import model.entities.Customer;
import model.repositories.CustomerRepository;
import model.service.interfaces.ICustomerService;
@Repository
@Transactional(readOnly = true)
public class CustomerService implements ICustomerService{
    @Autowired
    private CustomerRepository repository;

    // example method
    @Override
    public Customer getCustomer(Long customerId){
        return repository.findById(customerId);
    }

CustomerRepository - le référentiel pour Spring Data JPA

import javax.annotation.Resource;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.transaction.annotation.Transactional;
import model.entities.Customer;
@Resource
@Transactional(readOnly = true)
public interface CustomerRepository extends JpaRepository<Customer, Long>{

    public Customer findById(Long id);
}

Client - mon exemple d'entité

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "Customers")
public class Customer{

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name = "ID_CUSTOMER")
    private Long    id;

    @Column(name = "dbfirstname")
    private String  firstName;

    @Column(name = "dbname")
    private String  lastName;

    public Long getId(){
        return id;
    }

    public String getFirstName(){
        return firstName;
    }

    public void setFirstName(String firstName){
        this.firstName = firstName;
    }

    public String getLastName(){
        return lastName;
    }

    public void setLastName(String lastName){
        this.lastName = lastName;
    }
}

je viens de sortir de l'enfer classpath avec WebSphere (putain, quel produit fu ** ed up) et maintenant je suis ici. j'espère que quelqu'un pourra m'aider avec ça.

Une explication de base de ce qui se passe mal et peut-être fournir une meilleure compréhension de la fonction d'injection automatique des ressorts serait excellente. J'ai lu la documentation de Spring, mais pour dire la vérité: il y a tellement de façons de configurer quelque chose et ce n'est pas tout à fait visible pour moi CE QUI est vraiment nécessaire lors du choix d'un des styles de configuration.

[~ # ~] modifier [~ # ~]

Après avoir essayé de mettre à jour le projet, je reçois toujours l'erreur. comme demandé ici un peu plus de détails (trace):

Exception created : org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'customerService': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private model.repositories.CustomerRepository model.service.CustomerService.repository; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'customerRepository': FactoryBean threw exception on object creation; nested exception is Java.lang.NullPointerException
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.Java:287)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.Java:1106)
    [...]
        at com.ibm.ws.http.HttpConnection.run(HttpConnection.Java:522)
    at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.Java:1563)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private model.repositories.CustomerRepository model.service.CustomerService.repository; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'customerRepository': FactoryBean threw exception on object creation; nested exception is Java.lang.NullPointerException
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.Java:506)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.Java:87)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.Java:284)
    ... 96 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'customerRepository': FactoryBean threw exception on object creation; nested exception is Java.lang.NullPointerException
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.Java:149)
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.Java:102)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.Java:1442)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.Java:248)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.Java:193)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.Java:848)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.Java:790)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.Java:707)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.Java:478)
    ... 98 more
Caused by: Java.lang.NullPointerException
    at org.hibernate.engine.transaction.internal.jta.JtaStatusHelper.getStatus(JtaStatusHelper.Java:73)
    at org.hibernate.engine.transaction.internal.jta.JtaStatusHelper.isActive(JtaStatusHelper.Java:115)
    at org.hibernate.engine.transaction.internal.jta.CMTTransaction.join(CMTTransaction.Java:149)
    at org.hibernate.ejb.AbstractEntityManagerImpl.joinTransaction(AbstractEntityManagerImpl.Java:1215)
    at org.hibernate.ejb.AbstractEntityManagerImpl.postInit(AbstractEntityManagerImpl.Java:177)
    at org.hibernate.ejb.EntityManagerImpl.<init>(EntityManagerImpl.Java:89)
    at org.hibernate.ejb.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.Java:179)
    at org.hibernate.ejb.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.Java:174)
    at Sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at Sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.Java:48)
    at Sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.Java:25)
    at Java.lang.reflect.Method.invoke(Method.Java:600)
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.invokeProxyMethod(AbstractEntityManagerFactoryBean.Java:376)
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean$ManagedEntityManagerFactoryInvocationHandler.invoke(AbstractEntityManagerFactoryBean.Java:517)
    at $Proxy325.createEntityManager(Unknown Source)

    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.Java:234)
    at $Proxy328.createNamedQuery(Unknown Source)
    at org.springframework.data.jpa.repository.query.NamedQuery.<init>(NamedQuery.Java:74)
    at org.springframework.data.jpa.repository.query.NamedQuery.lookupFrom(NamedQuery.Java:96)
    at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$DeclaredQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.Java:128)
    at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateIfNotFoundQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.Java:162)
    at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$AbstractQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.Java:71)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.<init>(RepositoryFactorySupport.Java:303)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.Java:157)
    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:142)

EDIT # 2 compleate applicationContext.xml (y compris les modifications que j'ai apportées sur la base de la discussion en cours) ajouté comme demandé

<context:annotation-config />

<jpa:repositories base-package="model.repositories" />

<context:component-scan base-package="model,model.repositories,model.service,controller" />

<bean class="model.service.CustomerService"/>
<bean class="model.service.OrderService"/>
<bean class="model.repositories.CustomerRepository"/>
<bean class="model.repositories.OrderRepository"/>


<bean id="myExceptionTranslator" class="org.springframework.orm.hibernate4.HibernateExceptionTranslator" /> 

<jee:jndi-lookup id="dataSource" jndi-name="jdbc/mydata"
    resource-ref="true" cache="true" />


<bean id="pum"
    class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
    <property name="persistenceXmlLocations">
        <list>
            <value>classpath*:META-INF/OverridePersistence.xml</value>
        </list>
    </property>
    <property name="defaultDataSource" ref="dataSource" />
</bean>


<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="generateDdl" value="true" />
            <property name="database" value="MYSQL" />
        </bean>
    </property>
    <property name="persistenceUnitManager" ref="pum" />
    <property name="persistenceUnitName" value="default" />
</bean>

<bean id="mySessionFactory"
    class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="packagesToScan" value="model"/>
    <property name="hibernateProperties">
        <value>hibernate.dialect=org.hibernate.dialect.MySQLDialect</value>
    </property>
</bean>

<bean id="transactionManager"
    class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
    <property name="sessionFactory" ref="mySessionFactory" />
</bean>

<tx:annotation-driven />

<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
19
masi

Le problème est très probablement dans une partie de la configuration que vous n'avez pas montrée. Il serait également bon que vous signaliez l'erreur que vous obtenez. Cela pourrait être quelque chose de différent de ce que vous pensez.

Une chose que je remarque à propos de votre configuration est que vous utilisez context:annotation-config au lieu de context:component-scan. Ce dernier détectera automatiquement et créera des beans basés sur @Component famille d'annotations. Le premier ne fait pas ça.

En dehors de cela, tout ce que vous avez publié semble fonctionner, bien qu'il y ait plusieurs choses étranges, sur lesquelles je reviendrai dans un instant. J'ai copié tout votre code publié dans un exemple de projet et rempli quelques détails, comme un maven pom , un persistence.xml , et les pièces manquantes de l'applicationContext.xml . J'ai également ajouté une méthode "create" au service pour qu'il fasse réellement quelque chose. Avec ceux en place et une classe principale pour tout piloter, c'est un exemple exécutable. Vous pouvez parcourir le code sur github , ou vous pouvez cloner et l'exécuter avec:

git clone git://github.com/zzantozz/testbed tmp
cd tmp/stackoverflow/10539417-basic-spring-data-jpa
mvn -q compile exec:Java -Dexec.mainClass=rds.testbed.springDataJpa.SpringDataJp

Maintenant pour les bizarreries que j'ai remarquées. Du haut:

  • Avec le code tel qu'il est donné, il n'est pas nécessaire d'utiliser le PersistenceAnnotationBeanPostProcessor que vous avez ajouté au applicationContext.xml. Ça ne fait rien pour toi. Bien sûr, il peut y avoir un autre code qui en a besoin que vous n'avez pas montré.
  • Le @Repository l'annotation sur votre CustomerService est censée être utilisée sur les classes DAO , ou les classes qui interagissent avec une base de données. L'annotation appropriée pour un service est @Service .
  • Le @Resource l'annotation sur votre ICustomerRepository est principalement tilisée pour marquer les champs et les méthodes de câblage automatique . Je ne sais pas ce qui vous a fait penser à le mettre sur votre interface de référentiel, mais il n'y fait rien.
  • Votre référentiel ne doit pas être @Transactional. Cela appartient à votre service, et vous l'avez déjà là, donc ça va. Notez qu'il fonctionne toujours avec le @Transactional sur le référentiel car il rejoint simplement la transaction existante lancée par le service.
  • Il convient de noter à nouveau que vous n'utilisez pas numérisation des composants , même si vous avez un @Component- annotation associée (le @Repository à votre service). Cela pourrait vous causer des problèmes. Au lieu d'activer l'analyse des composants, j'ai créé manuellement le bean de service à l'aide de XML dans l'exemple de projet.

Donc ... si cela ne vous a pas expliqué quelque chose, si vous me donnez une erreur spécifique, je peux probablement expliquer pourquoi vous l'obtenez et vous dire quoi faire pour le corriger.

20
Ryan Stewart