web-dev-qa-db-fra.com

Comment récupérer JNDI à l'aide de Spring @Configuration au lieu de la configuration XML

J'ai commencé le développement d'une nouvelle application Spring 3.2.4 et j'essaie d'utiliser Java au lieu des fichiers XML comme je l'ai utilisé dans le passé. Cependant, j'ai du mal à faire le transition.

En utilisant XML, je le coderais comme suit:

<!-- application datasource -->
<bean id="dataSource.jndi" class="org.springframework.jndi.JndiObjectFactoryBean" scope="singleton" lazy-init="true">
    <property name="jndiName" value="Java:comp/env/jdbc/liment" />
</bean>

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

<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
    <property name="persistenceUnitName" value="persistenceUnit"/>
    <property name="dataSource" ref="dataSource.jndi"/>
</bean>

Cependant, je suis vraiment coincé à essayer de comprendre comment faire cela en Java. J'essaie de répliquer la configuration, mais j'ai des problèmes:

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages={"com.ia"})
public class AppConfigJPA {
    @Bean
    public DataSource dataSource() {
        // configure and return the necessary JDBC DataSource
        JndiObjectFactoryBean dataSource = new JndiObjectFactoryBean();
        dataSource.setJndiName("Java:comp/env/jdbc/liment");
        try {
            dataSource.afterPropertiesSet();
        } catch (IllegalArgumentException | NamingException e) {
            // rethrow
            throw new RuntimeException(e);
        }
        return (DataSource)dataSource.getObject();
    }

    @Bean
    public EntityManagerFactory entityManagerFactory(){
        LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
        emf.setPersistenceUnitName("persistenceUnit");
        emf.setDataSource(dataSource());
            emf.afterPropertiesSet
        return emf.getObject();
    }

    @Bean
    public PlatformTransactionManager transactionManager() {
        return new JpaTransactionManager(entityManagerFactory());
    }

}

Cependant, j'obtiens le message d'erreur suivant:

Caused by: Java.lang.IllegalStateException: No persistence exception translators found in bean factory. Cannot perform exception translation.
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.detectPersistenceExceptionTranslators(PersistenceExceptionTranslationInterceptor.Java:142)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.setBeanFactory(PersistenceExceptionTranslationInterceptor.Java:117)
    at org.springframework.data.repository.core.support.PersistenceExceptionTranslationRepositoryProxyPostProcessor.<init>(PersistenceExceptionTranslationRepositoryProxyPostProcessor.Java:44)
    at org.springframework.data.repository.core.support.TransactionalRepositoryFactoryBeanSupport.setBeanFactory(TransactionalRepositoryFactoryBeanSupport.Java:85)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeAwareMethods(AbstractAutowireCapableBeanFactory.Java:1502)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.Java:1470)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.Java:521)
    ... 33 more

Qu'est-ce que je manque ou fais mal?

MODIFIER

Suite à la réponse de @SotiriosDelimanolis, j'ai modifié mon code pour lire ce qui suit:

@Autowired DataSource dataSource;
@Autowired EntityManagerFactory entityManagerFactory;


@Bean
public JndiObjectFactoryBean dataSource() {
    // configure and return the necessary JDBC DataSource
    JndiObjectFactoryBean dataSource = new JndiObjectFactoryBean();
    dataSource.setJndiName("Java:comp/env/jdbc/josak");
    return dataSource;
}

@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(){
    LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
    emf.setPersistenceUnitName("persistenceUnit");
    emf.setDataSource(dataSource);
    return emf;
}

@Bean
public PlatformTransactionManager transactionManager() {
    return new JpaTransactionManager(entityManagerFactory);
}

Mais je reçois des exceptions Autowired à la place maintenant:

Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: javax.sql.DataSource com.ia.system.configuration.AppConfigJPA.dataSource; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.Java:514)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.Java:87)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.Java:285)
    ... 31 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.Java:988)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.Java:858)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.Java:770)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.Java:486)
    ... 33 more
13
Eric B.

veuillez vous référer au lien ci-dessous -

http://forum.spring.io/forum/spring-projects/container/724356-how-to-use-javaconfig-to-declare-a-jndi-datasource

la source de données doit être créée comme ceci -

@Bean
    public DataSource dataSource() {
        final JndiDataSourceLookup dsLookup = new JndiDataSourceLookup();
        dsLookup.setResourceRef(true);
        DataSource dataSource = dsLookup.getDataSource("jdbc/yourJdbcGoesHere");
        return dataSource;
    } 
24
Raj

C'est une conception bizarre (pour PersistenceExceptionTranslator) que je ne comprends pas immédiatement, mais voici la solution.

Votre LocalContainerEntityManagerFactoryBean est un FactoryBean mais aussi un PersistenceExceptionTranslator (implémente les deux). Mais vous ne mettez pas le LocalContainerEntityManagerFactoryBean dans votre contexte, vous obtenez seulement son objet créé.

Au lieu de

@Bean
public EntityManagerFactory entityManagerFactory(){
    LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
    emf.setPersistenceUnitName("persistenceUnit");
    emf.setDataSource(dataSource());
        emf.afterPropertiesSet
    return emf.getObject();
}

faire

@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(){
    LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
    emf.setPersistenceUnitName("persistenceUnit");
    emf.setDataSource(dataSource());
    return emf;
}

@Autowired
private EntityManagerFactory entityManagerFactory;

@Bean
public PlatformTransactionManager transactionManager() {
    return new JpaTransactionManager(entityManagerFactory);
}

Spring se chargera d'appeler afterPropertiesSet() et getObject() pour mettre un bean EntityManagerFactory dans le contexte.

Fondamentalement, vous vous retrouvez avec deux beans, un EntityManagerFactory et un LocalContainerEntityManagerFactoryBean. Votre configuration JPA nécessite un bean PersistenceExceptionTranslator dans le contexte. Cela sera satisfait par LocalContainerEntityManagerFactoryBean.


Pour info, vous pouvez faire la même chose pour votre JndiObjectFactoryBean ou tout autre FactoryBean.

1