web-dev-qa-db-fra.com

Aucun bean qualifiant de type [javax.persistence.EntityManager]

J'essaie de construire un tout nouveau projet Spring Framework 4.0 sans tous les trucs magiques de Gradle, mais je le lance simplement à l'ancienne.

Je suis le tutoriel ici: http://spring.io/guides/tutorials/data/ et j'ai un certain succès. Je suis simplement coincé à ce stade.

/**
 * 
 */
package com.corrisoft.air.db.integration;

import javax.persistence.EntityManager;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.transaction.annotation.Transactional;

import com.corrisoft.air.db.JPAConfiguration;

import static com.corrisoft.air.db.fixture.JPAAssertions.assertTableExists;
import static com.corrisoft.air.db.fixture.JPAAssertions.assertTableHasColumn;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { JPAConfiguration.class })
@Transactional
@TransactionConfiguration(defaultRollback = true)
public class PersonMappingIntegrationTests {

    @Autowired
    EntityManager manager;

    @Test
    public void thatItemCustomMappingWorks() throws Exception {
        assertTableExists(manager, "PERSONS");

        assertTableHasColumn(manager, "PERSONS", "FIRST_NAME");
        assertTableHasColumn(manager, "PERSONS", "LAST_NAME");
    }
}

Lorsque j'exécute ce test unitaire, j'obtiens la trace de pile suivante:

SEVERE: Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@68c884e] to prepare test instance [com.corrisoft.air.db.integration.PersonMappingIntegrationTests@7448bc3d]
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.corrisoft.air.db.integration.PersonMappingIntegrationTests': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: javax.persistence.EntityManager com.corrisoft.air.db.integration.PersonMappingIntegrationTests.manager; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.persistence.EntityManager] is defined: expected single matching bean but found 2: entityManager,org.springframework.orm.jpa.SharedEntityManagerCreator#0
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.Java:292)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.Java:1185)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties(AbstractAutowireCapableBeanFactory.Java:384)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.Java:110)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.Java:75)
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.Java:326)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.Java:212)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.Java:289)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.Java:12)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.Java:291)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.Java:232)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.Java:89)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.Java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.Java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.Java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.Java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.Java:229)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.Java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.Java:71)
    at org.junit.runners.ParentRunner.run(ParentRunner.Java:309)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.Java:175)
    at org.Eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.Java:50)
    at org.Eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.Java:38)
    at org.Eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.Java:467)
    at org.Eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.Java:683)
    at org.Eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.Java:390)
    at org.Eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.Java:197)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: javax.persistence.EntityManager com.corrisoft.air.db.integration.PersonMappingIntegrationTests.manager; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.persistence.EntityManager] is defined: expected single matching bean but found 2: entityManager,org.springframework.orm.jpa.SharedEntityManagerCreator#0
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.Java:508)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.Java:87)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.Java:289)
    ... 26 more
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.persistence.EntityManager] is defined: expected single matching bean but found 2: entityManager,org.springframework.orm.jpa.SharedEntityManagerCreator#0
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.Java:967)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.Java:855)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.Java:480)
    ... 28 more

Sur la base des observations suivies de recherches, il semblerait que cela me dit qu'il existe deux classes EntityManager. Le premier provient du pot JPA hiberné, mais ne trouve pas le second. Il semblerait me dire que c'est dans Spring ORM, mais il n'y a pas de définition dans cette classe.

Voici la classe JPAConfiguration utilisée dans le test:

/**
 * 
 */
package com.corrisoft.air.db;

import Java.sql.SQLException;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.orm.hibernate4.HibernateExceptionTranslator;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import com.corrisoft.air.db.repository.PersonsRepository;

/**
 * @author Corrisoft Android Development
 * 
 */
@Configuration
@EnableJpaRepositories(basePackages = "com.corrisoft.db.repository", includeFilters = @ComponentScan.Filter(value = { PersonsRepository.class }, type = FilterType.ASSIGNABLE_TYPE))
@EnableTransactionManagement
public class JPAConfiguration {

    @Bean
    public DataSource dataSource() throws SQLException {
        EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
        return builder.setType(EmbeddedDatabaseType.H2).build();
    }

    @Bean
    public EntityManagerFactory entityManagerFactory() throws SQLException {

        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        vendorAdapter.setGenerateDdl(true);

        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setJpaVendorAdapter(vendorAdapter);
        factory.setPackagesToScan("com.corrisoft.air.model");
        factory.setDataSource(dataSource());
        factory.afterPropertiesSet();

        return factory.getObject();
    }

    @Bean
    public EntityManager entityManager(EntityManagerFactory entityManagerFactory) {
        return entityManagerFactory.createEntityManager();
    }

    @Bean
    public PlatformTransactionManager transactionManager() throws SQLException {
        JpaTransactionManager txManager = new JpaTransactionManager();
        txManager.setEntityManagerFactory(entityManagerFactory());
        return txManager;
    }

    @Bean
    public HibernateExceptionTranslator hibernateExceptionTranslator() {
        return new HibernateExceptionTranslator();
    }
}
18
Thom

L'interface EntityManager appartient à JPA et est implémentée par les fournisseurs JPA (comme Eclipse), pas Spring, et elle a sa propre annotation d'injection: @PersistenceContext. EntityManager les objets ont une portée de transaction et ne doivent pas être exposés en tant que beans comme vous le faites. Utilisez plutôt l'annotation JPA pour injecter le EntityManager:

@PersistenceContext
EntityManager em;

ou, comme il semble que vous essayez d'utiliser des référentiels Spring, injectez le référentiel à la place:

@Autowired
PersonRepository pr;
26
chrylis

bien que cet article soit assez ancien et ait déjà répondu, j'ai rencontré le même problème avec le site officiel turorial spring-data-jpa sur le site web spring-io.

l'exemple de données de printemps en cours jpa/guide io de printemps détecte au moins 2 beans implémentant l'interface "EntityManager". Vous devez aider à créer une implémentation à câbler. Je recommande d'ajouter un qualificatif.

Dans la classe JPAConfiguration, ajoutez:

@Bean
@Qualifier(value = "entityManager")
public EntityManager entityManager(EntityManagerFactory entityManagerFactory) {
    return entityManagerFactory.createEntityManager();
}

Dans la classe de test, ajoutez:

@Autowired
@Qualifier(value = "entityManager")
EntityManager manager;

J'espère que cela vous aide.

Je n'utiliserais pas nécessairement le "PersistenceContext", car le printemps gère la création de gestionnaire de transactions, d'entitémanager, de beans, de source de données, etc.

6