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.
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());
}
}