javaspringspring-bootspring-mvceclipselink

springboot - init eclipseLink bean


I have this config bean:

@EnableTransactionManagement
@EnableJpaRepositories({ "com.soib.repositories",
        "com.notification.repositories"})
@Slf4j
@Configuration
public class EclipseLinkJpaConfiguration extends JpaBaseConfiguration {

    protected EclipseLinkJpaConfiguration(
            DataSource dataSource,
            JpaProperties properties,
            ObjectProvider<JtaTransactionManager> jtaTransactionManager) {

        super(dataSource, properties, jtaTransactionManager);
    }

    @Override
    protected AbstractJpaVendorAdapter createJpaVendorAdapter() {
        return new EclipseLinkJpaVendorAdapter();
    }

    @Bean
    @Primary
    public static JpaProperties properties() {
        final JpaProperties jpaProperties = new JpaProperties();
        jpaProperties.setShowSql(false);
        jpaProperties.setDatabasePlatform("org.eclipse.persistence.platform.database.OraclePlatform");
        return jpaProperties;
    }

    @Override
    protected Map<String, Object> getVendorProperties() {
        HashMap<String, Object> map = new HashMap<>();
        map.put(PersistenceUnitProperties.WEAVING, detectWeavingMode());
        return map;
    }

    private String detectWeavingMode() {
        return InstrumentationLoadTimeWeaver.isInstrumentationAvailable() ? "true" : "static";
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource, JpaVendorAdapter jpaVendorAdapter) {
        LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
        factoryBean.setDataSource(dataSource);
        factoryBean.setPersistenceUnitName("soib-backoffice-entities");
        factoryBean.setPackagesToScan("eu.europa.ec.oib.kwbo.model");
        factoryBean.setJpaVendorAdapter(jpaVendorAdapter);

        Properties jpaProperties = new Properties();
        jpaProperties.setProperty("eclipselink.target-database", "org.eclipse.persistence.platform.database.OraclePlatform");
        jpaProperties.setProperty("eclipselink.target-server", "WebLogic");
        jpaProperties.setProperty("eclipselink.logging.level", "WARNING");
        jpaProperties.setProperty("eclipselink.logging.level.sql", "WARNING");
        jpaProperties.setProperty("eclipselink.logging.logger", "DefaultLogger");
        jpaProperties.setProperty("eclipselink.cache.shared.default", "false");
        jpaProperties.setProperty("eclipselink.weaving", "false");
        jpaProperties.setProperty("eclipselink.jdbc.fetch-size", "200");

        factoryBean.setJpaProperties(jpaProperties);

        return factoryBean;
    }

    @Bean
    public JpaVendorAdapter jpaVendorAdapter() {
        EclipseLinkJpaVendorAdapter vendorAdapter = new EclipseLinkJpaVendorAdapter();
        vendorAdapter.setShowSql(false);
        vendorAdapter.setGenerateDdl(false);
        vendorAdapter.setDatabasePlatform("org.eclipse.persistence.platform.database.OraclePlatform");
        return vendorAdapter;
    }
}

but when I start the app, I have this error:

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#a30810': Cannot resolve reference to bean 'entityManagerFactory' while setting constructor argument; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:342)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:113)
    at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:688)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:505)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1352)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1195)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:374)
    ... 58 common frames omitted
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:874)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1358)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:309)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:330)

in my application.properties:

# JPA general settings
spring.jpa.show-sql=false
spring.jpa.generate-ddl=false
spring.jpa.database-platform=org.eclipse.persistence.platform.database.OraclePlatform

# EclipseLink-specific properties
spring.jpa.properties.eclipselink.target-database=org.eclipse.persistence.platform.database.OraclePlatform
spring.jpa.properties.eclipselink.target-server=WebLogic
spring.jpa.properties.eclipselink.logging.level=WARNING
spring.jpa.properties.eclipselink.logging.level.sql=WARNING
spring.jpa.properties.eclipselink.logging.logger=DefaultLogger
spring.jpa.properties.eclipselink.cache.shared.default=false
spring.jpa.properties.eclipselink.weaving=false
spring.jpa.properties.eclipselink.jdbc.fetch-size=200

Solution

  • I agree with M. Deinum. The spring.jpa properties is useless if you are providing your custom JPA configuration.

    You have to create and provide your custom PlatformTransactionManager and LocalContainerEntityManagerFactoryBean for custom JPA configuration.

    Modify to this:

    import jakarta.persistence.EntityManagerFactory;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
    import org.springframework.orm.jpa.JpaTransactionManager;
    import org.springframework.orm.jpa.JpaVendorAdapter;
    import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
    import org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter;
    import org.springframework.transaction.PlatformTransactionManager;
    import org.springframework.transaction.annotation.EnableTransactionManagement;
    
    import javax.sql.DataSource;
    import java.util.Properties;
    
    @Configuration
    @EnableTransactionManagement
    @EnableJpaRepositories(basePackages = {"com.soib.repositories", "com.notification.repositories"}, transactionManagerRef = "customTransactionManager")
    @Slf4j
    public class EclipseLinkJPAConfiguration {
    
        @Autowired
        private DataSource dataSource;
    
        @Bean
        public JpaVendorAdapter jpaVendorAdapter() {
            EclipseLinkJpaVendorAdapter vendorAdapter = new EclipseLinkJpaVendorAdapter();
            vendorAdapter.setShowSql(false);
            vendorAdapter.setGenerateDdl(false);
            vendorAdapter.setDatabasePlatform("org.eclipse.persistence.platform.database.OraclePlatform");
            return vendorAdapter;
        }
    
    
        @Bean
        public LocalContainerEntityManagerFactoryBean entityManagerFactory(JpaVendorAdapter jpaVendorAdapter) {
            LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
            factoryBean.setDataSource(dataSource);
            factoryBean.setPersistenceUnitName("soib-backoffice-entities");
            factoryBean.setPackagesToScan("eu.europa.ec.oib.kwbo.model");
            factoryBean.setJpaVendorAdapter(jpaVendorAdapter);
            factoryBean.setJpaProperties(jpaProperties());
            return factoryBean;
        }
    
        private Properties jpaProperties() {
            Properties jpaProperties = new Properties();
            jpaProperties.setProperty("eclipselink.target-database", "org.eclipse.persistence.platform.database.OraclePlatform");
            jpaProperties.setProperty("eclipselink.target-server", "WebLogic");
            jpaProperties.setProperty("eclipselink.logging.level", "WARNING");
            jpaProperties.setProperty("eclipselink.logging.level.sql", "WARNING");
            jpaProperties.setProperty("eclipselink.logging.logger", "DefaultLogger");
            jpaProperties.setProperty("eclipselink.cache.shared.default", "false");
            jpaProperties.setProperty("eclipselink.weaving", "false");
            jpaProperties.setProperty("eclipselink.jdbc.fetch-size", "200");
            return jpaProperties;
        }
    
        @Bean
        public EntityManagerFactory entityManagerFactory(LocalContainerEntityManagerFactoryBean entityManagerFactory) {
            return entityManagerFactory.getObject();
        }
    
        @Bean
        public PlatformTransactionManager customTransactionManager(EntityManagerFactory entityManagerFactory) {
            JpaTransactionManager transactionManager = new JpaTransactionManager();
            transactionManager.setEntityManagerFactory(entityManagerFactory);
            return transactionManager;
        }
    
    }
    

    See if this helps.

    Note: When you are doing DAO operations and you want to use your custom transaction manager, then you have to do this: @Transactional(transactionManager = "customTransactionManager")

    See if this helps.