2

I try to access a DataSource bean, declared as:

@Bean
@Primary
@ConfigurationProperties(prefix = "app.customer.datasource.properties")
public DataSource customerDataSource() {
    return customerDataSourceProperties().initializeDataSourceBuilder()
            .type(DataSource.class).build();
}

This works in Spring Boot 1.5 but if fails in Spring Boot 2.5 with the error:

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.sql.DataSource]: Specified class is an interface
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:119)
at org.springframework.boot.jdbc.DataSourceBuilder.build(DataSourceBuilder.java:75)
at demo.customer.CustomerConfig.customerDataSource(CustomerConfig.java:55)
at demo.customer.CustomerConfig$$EnhancerBySpringCGLIB$$1637ca06.CGLIB$customerDataSource$4(<generated>)
at demo.customer.CustomerConfig$$EnhancerBySpringCGLIB$$1637ca06$$FastClassBySpringCGLIB$$50f070a1.invoke(<generated>)

I also tried hardcoding the parameters (see below), but the error changed to NullPointerException.

@Bean
@Primary
public DataSource customerDataSource() {
    DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
    dataSourceBuilder.driverClassName("org.h2.Driver");
    dataSourceBuilder.url("jdbc:h2:mem:customers");
    dataSourceBuilder.username("SA");
    dataSourceBuilder.password("");
    return dataSourceBuilder.build();
}

The NPE exception I get is:

Caused by: java.lang.NullPointerException   
at org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter.determineDatabaseDialectClass(HibernateJpaVendorAdapter.java:185)   
at org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter.buildJpaPropertyMap(HibernateJpaVendorAdapter.java:143)     
at org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter.getJpaPropertyMap(HibernateJpaVendorAdapter.java:127)   
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:346)   
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:341)
....

I also see the same NPE if I choose ".type(HikariDataSource.class)".

Do you have any idea what changed since version 1.5?

2 Answers 2

1

You can provide a configuration class and register a bean like below :

@Configuration
public class DataSourceConfig {

    @Bean
    public DataSource getDataSource() {
        DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
        dataSourceBuilder.driverClassName("org.h2.Driver");
        dataSourceBuilder.url("jdbc:h2:mem:test");
        dataSourceBuilder.username("SA");
        dataSourceBuilder.password("");
        return dataSourceBuilder.build();
    }
}

You can also provide the values in application.yml or application.properties in springboot if you have spring-boot-starter-data-jpa as dependency and springboot will automatically create the datasource bean for you. application.properties

spring.datasource.url=jdbc:h2:your:url
spring.datasource.driver-class-name=org.h2.Driver

For your case , the error :

Caused by: java.lang.NullPointerException   
at org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter.determineDatabaseDialectClass(HibernateJpaVendorAdapter.java:185)  

occurs because the method determineDatabaseDialectClass() returns the Hibernate database dialect class, or null if none found.

Official doc

So,try adding the following in application.properties to set the dialect or add it programatically :

spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQLDialect

or using a programatically using bean like :

@Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(){
        LocalContainerEntityManagerFactoryBean factoryBean
            = new LocalContainerEntityManagerFactoryBean();

        factoryBean.setDataSource( this.restDataSource() );
        factoryBean.setPackagesToScan( new String[ ] { "com.jverstry" } );
        factoryBean.setPersistenceUnitName("MyMy");

        Properties props = new Properties();
        props.put("hibernate.dialect",  "org.hibernate.dialect.MySQLDialect");
        props.put("hibernate.hbm2ddl.auto", "create");
        factoryBean.setJpaProperties(props);
        return factoryBean;
    }

Usually springoot by default takes care of this and provides default implementation for this , if you have provided all the values in the property files etc. You could also configure this through xml but since it is springboot configurations through java are much appreciated.

Sign up to request clarification or add additional context in comments.

4 Comments

This is exactly what I did as 2nd option when I hardcoded the parameters in customerDataSource. I get a NullPonterException.
@user3429660 Sorry missed that part,have updated the answer
thanks for looking into this. After adding hibernate.dialect I see the exact same errors. :(
@user3429660Basically there is some configuration issue in your code ,otherwise the default implementation should have worked fine.Try setting it through bean creation ,i have provided an example.
1

Building on Ananthapadmanabhan's answer, here is the code I finally used:

@Bean
public DataSource orderDataSource() {
    DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
    dataSourceBuilder.driverClassName("org.h2.Driver");
    dataSourceBuilder.url("jdbc:h2:mem:orders");
    dataSourceBuilder.username("SA");
    dataSourceBuilder.password("");
    return dataSourceBuilder.build();
}

@Bean(name = "orderEntityManager")
public LocalContainerEntityManagerFactoryBean orderEntityManagerFactory() {
    HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
    vendorAdapter.setDatabasePlatform("org.hibernate.dialect.H2Dialect");
    vendorAdapter.setGenerateDdl(true);

    LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
    factoryBean.setJpaVendorAdapter(vendorAdapter);
    factoryBean.setDataSource(this.orderDataSource());
    factoryBean.setPackagesToScan("demo.order");
    factoryBean.setPersistenceUnitName("order");

    return factoryBean;
}

@Bean
public JpaTransactionManager orderTransactionManager(EntityManagerFactory orderEntityManager) {
    return new JpaTransactionManager(orderEntityManager);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.