2

I know it is possible to change the JPA implementation in use by Spring Boot, the default is to use Hibernate, but it's also possible to user others, like EclipseLink. It is possible to find, at application runtime, which JPA implementation is being used, and also discover which SQL dialect is currently in use (like MySQL, PostgreSQL, Oracle)?

André Shevantes
  • 439
  • 2
  • 5
  • 14
  • 2
    Depends upon what you mean by run time. If you have access to application logs, it may be possible to find the details. – royalghost Apr 17 '19 at 00:42
  • 1
    So you can just check the real implementing type of `EntityManager` to determine the JPA implementation. And finding out the dialect is JPA provider dependent. – Amir Pashazadeh Apr 17 '19 at 01:08

3 Answers3

2

As stated by @Prabin, if you have access to the application logs, you should be able to grep for 'dialect' and come away with both the JPA Vendor and the Dialect in use.

2019-04-17 02:02:55.061  INFO 12724 --- [           main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.SQLServer2012Dialect

If you have access to the code, the easier thing to do would just be to review the configuration, but since you asked about programmatic determination, there are a couple of things you could do (assuming you can access Spring Beans in your code either via the ApplicationContext or by injection).

Using the ApplicationContext to access the JpaVendorAdapter Bean I can determine my JPA vendor to be org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter, but the dialect details are less helpful:

public static void main( String[] args ) {
        SpringApplication springApplication = new SpringApplication( DevicePeersApplication.class );
        ConfigurableApplicationContext appContext = springApplication.run( args );
        JpaVendorAdapter jpaVendorAdapter = appContext.getBean( JpaVendorAdapter.class );
        log.debug( "JPA Vendor Adapter: {}", jpaVendorAdapter.getClass().getName() );
        log.debug( "JPA Dialect: {}", jpaVendorAdapter.getJpaDialect().getClass().getName() );
        ...
}

2019-04-17 02:02:59.226 DEBUG 12724 --- [           main] c.c.n.d.Application           : JPA Vendor Adapter: org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter
2019-04-17 02:02:59.226 DEBUG 12724 --- [           main] c.c.n.d.Application           : JPA Dialect: org.springframework.orm.jpa.vendor.HibernateJpaDialect

Knowing that the JpaVendorAdapter is org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter, I now know that the properties on the EntityManagerFactory that I'm interested in will be prefixed with hibernate., in your case specifically hibernate.dialect. You will have to look up the specifics for alternative JPA implementations like EclipseLink.

EntityManagerFactory entityManagerFactory = appContext.getBean( "entityManagerFactory", EntityManagerFactory.class );

String dialect = (String) entityManagerFactory.getProperties().getOrDefault( "hibernate.dialect", "" );

log.debug( "{}={}", "hibernate.dialect", dialect );


2019-04-17 02:02:59.228 DEBUG 12724 --- [           main] c.c.n.d.Application           : hibernate.dialect=org.hibernate.dialect.SQLServer2012Dialect

For completeness, you could pull all Hibernate-specific properties with the following, replacing 'hibernate.' with another property prefix as needed for other JPA implementations:

entityManagerFactory
            .getProperties()
            .entrySet()
            .stream()
            .filter( entry -> entry.getKey().startsWith( "hibernate." ) )
            .forEach( entry -> log.debug( entry.toString() ) );

Finally, since JpaVendorAdapter and EntityManagerFactory are Spring Beans, you could just inject them into another part of your code and deal with them there:

@Autowired
JpaVendorAdapter jpaVendorAdapter;

@Autowired
EntityManagerFactory entityManagerFactory;

void myMethod() {
    entityManagerFactory.getProperties()...
}
Philip Wrage
  • 1,505
  • 1
  • 12
  • 23
1

You could dig through the AutowireCapableBeanFactory. You could get the JpaBaseConfiguration.class bean. Then check the jpaVendorAdapter and the jpaDialect. That may work. Here is an example @RestController.

@RestController
class JpaConfigResource {

  @Autowired
  private ApplicationContext applicationContext;

  @RequestMapping("/jpa")
  Map<String, String> getJpaConfig() {

    JpaBaseConfiguration jpaConfig = null;
    String jpaVendorAdapter = "Not Found";
    String jpaDialect = "Not Found";
    Map<String, String> result = new HashMap<>();

    AutowireCapableBeanFactory autowireCapableBeanFactory = applicationContext.getAutowireCapableBeanFactory();

    if (autowireCapableBeanFactory != null) {
      jpaConfig = autowireCapableBeanFactory.getBean(JpaBaseConfiguration.class);
    } else {
      System.out.println("autowireCapableBeanFactory was not found...");
    }

    if (jpaConfig != null) {
      jpaVendorAdapter = jpaConfig.jpaVendorAdapter().getClass().getName();
      jpaDialect = jpaConfig.jpaVendorAdapter().getJpaDialect().getClass().getName();
    } else {
      System.out.println("jpaConfig was not found...");
    }

    result.put("jpaVendorAdapter", jpaVendorAdapter);
    result.put("jpaDialect", jpaDialect);

    System.out.println("result => " + result.toString());

    return result;
  }
}
thesb
  • 219
  • 1
  • 6
1

Another possible solution would be to inspect the JDBC string from the application.yml file :-)

Robert
  • 1,579
  • 1
  • 21
  • 36
  • or see here: https://stackoverflow.com/questions/27181397/how-to-get-hibernate-dialect-during-runtime – Robert Feb 16 '20 at 09:28