Search code examples
javaspring-boothibernategraalvm

RuntimeHint for Hibernate Db2Dialect with Spring Boot and GraalVM


I am trying to get the Db2Dialect working with Hibernate. I am using Sprint Boot 3.0.2 and the GraalVm version 22.3.1. Adding the hibernate-graalvm dependency did not help either. When starting the native image I get the following error:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory': Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment]
[...]
Caused by: org.hibernate.boot.registry.selector.spi.StrategySelectionException: Could not instantiate named strategy class [org.hibernate.dialect.DB2Dialect]
        at org.hibernate.boot.registry.selector.internal.StrategySelectorImpl.resolveStrategy(StrategySelectorImpl.java:245) ~[na:na]
        at org.hibernate.boot.registry.selector.internal.StrategySelectorImpl.resolveStrategy(StrategySelectorImpl.java:190) ~[na:na]
        at org.hibernate.engine.jdbc.dialect.internal.DialectFactoryImpl.constructDialect(DialectFactoryImpl.java:96) ~[spinsample-maven-local-v1:6.1.7.Final]
        at org.hibernate.engine.jdbc.dialect.internal.DialectFactoryImpl.buildDialect(DialectFactoryImpl.java:59) ~[spinsample-maven-local-v1:6.1.7.Final]
        at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:244) ~[na:na]
        at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:36) ~[na:na]
        at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.initiateService(StandardServiceRegistryImpl.java:119) ~[na:na]
        at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:255) ~[spinsample-maven-local-v1:6.1.7.Final]
        ... 32 common frames omitted
Caused by: org.hibernate.boot.registry.selector.spi.StrategySelectionException: Could not instantiate named dialect class [org.hibernate.dialect.DB2Dialect]
        at org.hibernate.engine.jdbc.dialect.internal.DialectFactoryImpl.lambda$constructDialect$0(DialectFactoryImpl.java:116) ~[spinsample-maven-local-v1:6.1.7.Final]
        at org.hibernate.boot.registry.selector.internal.StrategySelectorImpl.resolveStrategy(StrategySelectorImpl.java:241) ~[na:na]
        ... 39 common frames omitted
Caused by: java.lang.InstantiationException: org.hibernate.dialect.DB2Dialect
        at java.base@17.0.6/java.lang.Class.newInstance(DynamicHub.java:639) ~[spinsample-maven-local-v1:na]
        at org.hibernate.engine.jdbc.dialect.internal.DialectFactoryImpl.lambda$constructDialect$0(DialectFactoryImpl.java:112) ~[spinsample-maven-local-v1:6.1.7.Final]
        ... 40 common frames omitted
Caused by: java.lang.NoSuchMethodException: org.hibernate.dialect.DB2Dialect.<init>()
        at java.base@17.0.6/java.lang.Class.getConstructor0(DynamicHub.java:3585) ~[spinsample-maven-local-v1:na]
        at java.base@17.0.6/java.lang.Class.newInstance(DynamicHub.java:626) ~[spinsample-maven-local-v1:na]
        ... 41 common frames omitted

That is why I have tried to create a RuntimeHint. To my understanding, the class Db2Dialect has a protected constructor and can only be called via a member variable that acts as a singleton instance. And that's probably what I need to express with the RuntimeHint.

hints.reflection().registerType(Db2Dialect.class, MemberCategory.values());
Constructor<Db2Dialect> cons = Db2Dialect.class.getDeclaredConstructor();
hints.reflection().registerConstructor(cons, ExecutableMode.INVOKE);

But that didn't work for me and the documentation on RuntimeHints didn't help me either.


Solution

  • So, I found the issue with my hint. Instead of using org.hibernate.dialect.DB2Dialect my hint imported org.springframework.data.relational.core.dialect.Db2Dialect (with an lowercase b). Therefore, the correct hint looks like this:

    import org.springframework.aot.hint.MemberCategory;
    import org.springframework.aot.hint.RuntimeHints;
    import org.springframework.aot.hint.RuntimeHintsRegistrar;
    import org.hibernate.dialect.DB2Dialect;
    
    public class MyNativeHints implements RuntimeHintsRegistrar
    {
        hints.reflection()
             .registerType(DB2Dialect.class, MemberCategory.values());
        
    }
    

    }