2012-05-10 7 views
17

Ho seguito il tutorial pubblicato here per ottenere un'applicazione di base che funzioni con Spring Data JPA. Ora, come ho capito, utilizzando la configurazioneSpring Data JPA - iniezione fallita - BeanCreationException: Impossibile eseguire il campo autoporto

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

dovrebbe tradursi in quel pacchetto beeing scansionato entro la primavera dati JPA per le interfacce estendono JpaRepository e creare un fagiolo concreate di esso in modo che possa essere utilizzato ovunque nelle mie classi di servizio utilizzando semplici Primavera @Autowired. Ma fallisce, dicendo che non può trovare un bean con className (che è il nome predefinito che il bean ottiene quando viene creato, semplicemente usando il ClassName decapitalizzato).

Tuttavia, quando configuro il fagiolo manualy nel mio applicationContext come questo:

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

La primavera è in grado di trovare il fagiolo. Ovviamente ottengo un errore perché voglio creare un bean da un'interfaccia, che ovviamente non può funzionare. MA il punto è che sembra che la "creazione automatica dei bean" di Spring Data JPA sembra in qualche modo fallire.

Ho allegato il codice pertinente in modo da poterlo vedere. A proposito, dovrei menzionare che sto sviluppando un portlet, quindi non mi chiedo perché non ho una primavera-config. Attualmente sto usando un applicationConfig più un MyPortlet-Portlet.xml per le configurazioni del portlet (ma questo non dovrebbe essere rilevante per questo problema). Ho aggiunto le istruzioni di importazione solo per assicurarmi che non stia usando le lezioni/classi errate.

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 - solo un'interfaccia per la CustomerService

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

CustomerService - la classe usata da mia logica dell'applicazione per ottenere/set di dati 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 - il repository per la primavera dati 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); 
} 

cliente - la mia entità campione

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; 
    } 
} 

Sono appena tornato dall'inferno classpath con WebSphere (maledetto, che fu * * ed up prodotto) e ora sono qui. Spero che qualcuno possa aiutarmi con questo.

Una spiegazione di base di ciò che esattamente va storto e che forse fornisce una migliore comprensione della funzione di iniezione a molle auto sarebbe grande. Ho letto la documentazione di primavera, ma a dire il vero: ci sono tanti modi per configurare qualcosa e non è abbastanza visibile per me COSA è veramente necessario quando si sceglie uno degli stili di configurazione.

EDIT

Dopo aver cercato di aggiornare il progetto a cui sto ancora ricevendo l'errore.come richiesto qui un po 'più particolari (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 (includeing i cambiamenti che ho fatto Sulla base della discussione in corso) aggiunto come richiesto

<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" /> 
+0

Il tuo CustomerRepository non ha bisogno dell'annotazione della risorsa. Inoltre, findById dovrebbe già essere fornito da JpaRepository. Suppongo che il tuo entityManager sia stato creato correttamente senza errori. Con dovrebbe essere sufficiente. Attiva il registro di debug per le classi Spring e controlla se c'è qualche errore lì. – Luciano

+0

Perché il CustomerService ha l'annotazione del repository anziché l'annotazione del servizio? – Luciano

+0

controlla i miei commenti sulla risposta di Ryan Stewart. in sostanza perché ho seguito il tutorial che sembra essere incompleto. – masi

risposta

19

Il problema è molto probabilmente in alcune delle configurazioni che non hai mostrato. Sarebbe anche positivo se hai postato l'errore che stai ricevendo. Potrebbe essere qualcosa di diverso da quello che pensi che sia.

Una cosa che noto della configurazione è che si utilizza context:annotation-config anziché context:component-scan. Quest'ultimo rileverà e creerà automaticamente i bean in base alla famiglia di annotazioni @Component. Il primo non lo fa.

A parte questo, tutto quello che hai pubblicato sembra funzionare, anche se ci sono molte cose strane, che arriverò tra un momento. Ho copiato tutto il codice postato in un progetto di esempio e ho inserito alcuni dettagli, ad esempio maven pom, uno persistence.xml e i pezzi mancanti di the applicationContext.xml. Ho anche aggiunto un metodo "crea" al servizio in modo che potesse effettivamente fare qualcosa. Con quelli sul posto e una classe principale per guidarli tutti, è un esempio percorribile. È possibile browse the code on github, oppure si può clonare ed eseguirlo con:

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 

Ora per le stranezze che ho notato. Dall'alto:

  • Con il codice come data, non c'è bisogno per il PersistenceAnnotationBeanPostProcessor che hai aggiunto al applicationContext.xml. Non sta facendo nulla per te. Certo, potrebbe esserci un altro codice che ne ha bisogno che non hai mostrato.
  • L'annotazione @Repository sul CustomerService è supposed to be used on DAO classes o le classi che interagiscono con un database. L'annotazione appropriata per un servizio è @Service.
  • L'annotazione @Resource sul proprio repository di dati IC è principalmente used for marking fields and methods for autowiring. Non sono sicuro di cosa ti abbia fatto pensare di metterlo sull'interfaccia del tuo repository, ma non sta facendo nulla lì.
  • Il repository non deve essere @Transactional. Questo è al tuo servizio, e tu ce l'hai già, quindi va bene. Si noti che funziona ancora con lo @Transactional sul repository perché si collega alla transazione esistente avviata dal servizio.
  • Vale la pena notare che non si sta utilizzando component scanning, anche se si dispone di un'annotazione relativa a @Component (il servizio @Repository). Questo potrebbe causare alcuni problemi. Invece di attivare la scansione dei componenti, ho creato manualmente il bean dei servizi utilizzando XML nel progetto di esempio.

Quindi ... se questo non ti ha spiegato qualcosa, se mi dai un errore specifico, posso probabilmente spiegare perché lo stai ricevendo e ti dico cosa fare per farlo bene.

+0

passerò attraverso il tuo codice e dare un'occhiata. finora per le vostre domande: - a destra, sembra che non ho bisogno di PersistenceAnnotationBeanPostProcessor. Per il debug sono andato con "prova di più e rimuovi ciò di cui non hai bisogno dopo che ha funzionato" - la cosa del repository è strana, lo so. ma il tutorial che ho postato (prima frase nella mia domanda) afferma che è giusto dal momento che la classe IS è un repository anche se il suo servizio chiamato - Ho rimosso l'annotazione della risorsa dall'IFace - L'annotazione Transcational è anche indicata nel tutorial - non sapevo che avrei dovuto usare la scansione dei componenti insted of the anno conf – masi

+0

Il tag 'component-scan' [è un superset di' annotation-config'] (http://static.springsource.org/spring/ docs/3.0.x/primavera-quadro di riferimento/html/beans.html # fagioli-java-combina-xml-centric-component-scan). Lo fa, oltre alla scansione per le classi annotate da qualsiasi annotazione relativa a '@ Componente'. –

+0

Il post del blog che stavi seguendo sosteneva che il "servizio" era un repository perché aveva inserito un EntityManager, rendendolo un "repository" tradizionale. Ha anche menzionato l'intenzione di introdurre un vero repository più avanti, anche se non sembra averlo capito. Il tuo CustomerService viene iniettato con un CustomerRepository, quindi chiaramente quello è un '@ Service' e l'altro è un' @ Repository'. –

Problemi correlati