BigONotation
BigONotation

Reputation: 4538

How to include postgres driver in spring AOT compilation using spring boot 3.0.0-RC2

I have written a very simple service that I am trying to run as a native executable using Graal VM. The service uses spring data with a Postgres backend. The following plugins are included in my build.gradle configuration:

plugins {
   id 'java'
   id 'org.springframework.boot' version '3.0.0-RC2'
   id 'io.spring.dependency-management' version '1.1.0'
   id 'org.hibernate.orm' version '6.1.5.Final'
   id 'org.graalvm.buildtools.native' version '0.9.17'
}

I have also included the following dependencies:

dependencies {
   implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
   implementation 'org.springframework.boot:spring-boot-starter-validation'
   implementation 'org.springframework.boot:spring-boot-starter-web'
   runtimeOnly 'org.postgresql:postgresql'
   testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

I am building a native image so that it can be executed as a docker container: ./gradlew bootBuildImage.

When I try to run the docker image, I am getting the following exception:

java.lang.NoSuchMethodException: org.postgresql.util.PGobject.<init>()
    at [email protected]/java.lang.Class.getConstructor0(DynamicHub.java:3585) ~[com.avisuite.airports.AirportsService:na]
    at [email protected]/java.lang.Class.getConstructor(DynamicHub.java:2271) ~[com.avisuite.airports.AirportsService:na]
    at org.hibernate.dialect.PostgreSQLPGObjectJdbcType.<clinit>(PostgreSQLPGObjectJdbcType.java:50) ~[com.avisuite.airports.AirportsService:6.1.5.Final]
    at org.hibernate.dialect.PostgreSQLDialect.registerColumnTypes(PostgreSQLDialect.java:231) ~[com.avisuite.airports.AirportsService:6.1.5.Final]
    at org.hibernate.dialect.Dialect.contributeTypes(Dialect.java:1341) ~[com.avisuite.airports.AirportsService:6.1.5.Final]
    at org.hibernate.dialect.PostgreSQLDialect.contributeTypes(PostgreSQLDialect.java:1229) ~[com.avisuite.airports.AirportsService:6.1.5.Final]
    at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.handleTypes(MetadataBuildingProcess.java:386) ~[na:na]
    at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:143) ~[na:na]
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:1350) ~[com.avisuite.airports.AirportsService:6.1.5.Final]
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1421) ~[com.avisuite.airports.AirportsService:6.1.5.Final]
    at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:66) ~[na:na]
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:376) ~[com.avisuite.airports.AirportsService:6.0.0-RC4]
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:409) ~[com.avisuite.airports.AirportsService:6.0.0-RC4]
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:396) ~[com.avisuite.airports.AirportsService:6.0.0-RC4]
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:352) ~[com.avisuite.airports.AirportsService:6.0.0-RC4]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1799) ~[com.avisuite.airports.AirportsService:6.0.0-RC4]

I am assuming that the required postgres driver classes were not correctly packaged as part of the native executable. However, I am not sure how to proceed in order to include them.

Edit:

I changed my postgres dependency from runtimeOnly 'org.postgresql:postgresql' to aotRuntimeOnly 'org.postgresql:postgresql' and now I am getting a different exception:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'dataSourceScriptDatabaseInitializer': Unsatisfied dependency expressed through method 'dataSourceScriptDatabaseInitializer' parameter 0: Error creating bean with name 'dataSource': Instantiation of supplied bean failed
    at org.springframework.beans.factory.aot.BeanInstanceSupplier.resolveArgument(BeanInstanceSupplier.java:351) ~[na:na]
    at org.springframework.beans.factory.aot.BeanInstanceSupplier.resolveArguments(BeanInstanceSupplier.java:271) ~[na:na]
    at org.springframework.beans.factory.aot.BeanInstanceSupplier.get(BeanInstanceSupplier.java:206) ~[na:na]
  

Upvotes: 3

Views: 748

Answers (1)

Jakub
Jakub

Reputation: 89

The exception is thrown from the PostgreSQLPGObjectJdbcType class.

Source code points to what you need to register a class:

ReflectHelper.classForName(
                    "org.postgresql.util.PGobject",
                    PostgreSQLPGObjectJdbcType.class
            );

Can you try to add your own Hints class (https://www.baeldung.com/spring-native-intro#1-sample-jacksons-propertynamingstrategy):

@Configuration
@ImportRuntimeHints(NativeImageRuntimeHints.HibernateRegistrar.class)
public class NativeImageRuntimeHints {
    static class HibernateRegistrar implements RuntimeHintsRegistrar {
        @Override
        public void registerHints(org.springframework.aot.hint.RuntimeHints hints, ClassLoader classLoader) {
            try {
                hints.reflection()
                        .registerType(PGobject.class,
                                hint -> hint.withMembers(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS, MemberCategory.INTROSPECT_PUBLIC_METHODS)
                                        .onReachableType(PostgreSQLPGObjectJdbcType.class));
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
}

Btw. Spring Boot 3.0.0 has already been released.

Upvotes: 2

Related Questions