Search code examples
spring-boothibernatejpaspring-boot-nativejava-native

Unable to run Spring Boot native application with InheritanceType.JOINED


I'm trying to run an existing Spring Boot application natively, but I'm getting this exception:

2025-01-15T13:08:24.069-03:00  WARN 61583 --- [core] [           main] w.s.c.ServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory': [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.MappingException: Could not find appropriate constructor for org.hibernate.persister.entity.JoinedSubclassEntityPersister

Stacktrace:

:: Spring Boot ::                (v3.4.1)

2025-01-15T13:08:23.419-03:00  INFO 61583 --- [core] [           main] b.c.digital.core.CoreApplication  : Starting AOT-processed CoreApplication using Java 21.0.2 with PID 61583 (/home/fjaekel/git/digital/digital-core/backend/digital-core-backend/target/digital-core-backend started by fjaekel in /home/fjaekel/git/digital/digital-core/backend/digital-core-backend)
2025-01-15T13:08:23.419-03:00  INFO 61583 --- [core] [           main] b.c.digital.core.CoreApplication  : The following 1 profile is active: "skip-migrations"
2025-01-15T13:08:23.424-03:00  INFO 61583 --- [core] [           main] o.s.cloud.context.scope.GenericScope     : BeanFactory id=0cfe84c1-9d59-39cc-92c1-04cef9915c66
2025-01-15T13:08:23.520-03:00  WARN 61583 --- [core] [           main] io.undertow.websockets.jsr               : UT026010: Buffer pool was not set on WebSocketDeploymentInfo, the default pool will be used
2025-01-15T13:08:23.520-03:00  INFO 61583 --- [core] [           main] io.undertow.servlet                      : Initializing Spring embedded WebApplicationContext
2025-01-15T13:08:23.520-03:00  INFO 61583 --- [core] [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 101 ms
2025-01-15T13:08:23.591-03:00  INFO 61583 --- [core] [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2025-01-15T13:08:23.601-03:00  INFO 61583 --- [core] [           main] com.zaxxer.hikari.pool.HikariPool        : HikariPool-1 - Added connection org.postgresql.jdbc.PgConnection@79c08e62
2025-01-15T13:08:23.601-03:00  INFO 61583 --- [core] [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2025-01-15T13:08:23.604-03:00  INFO 61583 --- [core] [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [name: default]
2025-01-15T13:08:23.605-03:00  INFO 61583 --- [core] [           main] org.hibernate.Version                    : HHH000412: Hibernate ORM core version 6.6.4.Final
2025-01-15T13:08:23.607-03:00  INFO 61583 --- [core] [           main] o.h.c.internal.RegionFactoryInitiator    : HHH000026: Second-level cache disabled
2025-01-15T13:08:23.788-03:00  INFO 61583 --- [core] [           main] org.hibernate.orm.connections.pooling    : HHH10001005: Database info:
        Database JDBC URL [undefined/unknown]
        Database driver: undefined/unknown
        Database version: 17.2
        Autocommit mode: undefined/unknown
        Isolation level: undefined/unknown
        Minimum pool size: undefined/unknown
        Maximum pool size: undefined/unknown
2025-01-15T13:08:24.069-03:00 ERROR 61583 --- [core] [           main] j.LocalContainerEntityManagerFactoryBean : Failed to initialize JPA EntityManagerFactory: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.MappingException: Could not find appropriate constructor for org.hibernate.persister.entity.JoinedSubclassEntityPersister
2025-01-15T13:08:24.069-03:00  WARN 61583 --- [core] [           main] w.s.c.ServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory': [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.MappingException: Could not find appropriate constructor for org.hibernate.persister.entity.JoinedSubclassEntityPersister
2025-01-15T13:08:24.069-03:00  INFO 61583 --- [core] [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
2025-01-15T13:08:24.070-03:00  INFO 61583 --- [core] [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.
Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory': [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.MappingException: Could not find appropriate constructor for org.hibernate.persister.entity.JoinedSubclassEntityPersister
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1808)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523)
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:336)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:289)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:334)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204)
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:970)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:627)
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146)
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:752)
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:439)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:318)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1361)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1350)
        at br.com.digital.core.CoreApplication.main(CoreApplication.java:11)
        at [email protected]/java.lang.invoke.LambdaForm$DMH/sa346b79c.invokeStaticInit(LambdaForm$DMH)
Caused by: jakarta.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.MappingException: Could not find appropriate constructor for org.hibernate.persister.entity.JoinedSubclassEntityPersister
        at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:431)
        at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:400)
        at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:366)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1855)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1804)
        ... 16 more
Caused by: org.hibernate.MappingException: Could not find appropriate constructor for org.hibernate.persister.entity.JoinedSubclassEntityPersister
        at org.hibernate.persister.internal.PersisterFactoryImpl.resolveEntityPersisterConstructor(PersisterFactoryImpl.java:140)
        at org.hibernate.persister.internal.PersisterFactoryImpl.createEntityPersister(PersisterFactoryImpl.java:92)
        at org.hibernate.persister.internal.PersisterFactoryImpl.createEntityPersister(PersisterFactoryImpl.java:77)
        at org.hibernate.metamodel.model.domain.internal.MappingMetamodelImpl.processBootEntities(MappingMetamodelImpl.java:250)
        at org.hibernate.metamodel.model.domain.internal.MappingMetamodelImpl.finishInitialization(MappingMetamodelImpl.java:184)
        at org.hibernate.internal.SessionFactoryImpl.initializeMappingModel(SessionFactoryImpl.java:373)
        at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:302)
        at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:463)
        at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1506)
        at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:66)
        at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:390)
        at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:419)
        ... 20 more
Caused by: java.lang.NoSuchMethodException: org.hibernate.persister.entity.JoinedSubclassEntityPersister.<init>(org.hibernate.mapping.PersistentClass, org.hibernate.cache.spi.access.EntityDataAccess, org.hibernate.cache.spi.access.NaturalIdDataAccess, org.hibernate.metamodel.spi.RuntimeModelCreationContext)
        at [email protected]/java.lang.Class.checkMethod(DynamicHub.java:1075)
        at [email protected]/java.lang.Class.getConstructor0(DynamicHub.java:1238)
        at [email protected]/java.lang.Class.getConstructor(DynamicHub.java:2442)
        at org.hibernate.persister.internal.PersisterFactoryImpl.resolveEntityPersisterConstructor(PersisterFactoryImpl.java:115)
        ... 31 more

Sample from the application entity inheritance:

@Getter
@Setter
@ToString(onlyExplicitlyIncluded = true)
@Entity
@NoArgsConstructor
@Table(name = "composition_answer")
@Inheritance(strategy = InheritanceType.JOINED)
public class CompositionAnswer extends EntryIntegratableMultiTenantEntity

@Getter
@Setter
@ToString(onlyExplicitlyIncluded = true)
@Entity
@Table(name = "composition_allergy_answer")
@PrimaryKeyJoinColumn(name = "id")
@NoArgsConstructor
public class CompositionAllergyAnswer extends CompositionAnswer

Do I need additional configuration to use native builds with InheritanceType.JOINED?

Tested with Spring Boot 3.4.1 and 3.3.7. The application runs fine with a regular build.

Thanks


Solution

  • The JoinedSubclassEntityPersister metadata is missing for latests Hibernate releases: https://github.com/search?q=repo%3Aoracle%2Fgraalvm-reachability-metadata+JoinedSubclassEntityPersister&type=code

    Copying it from here and adding to the project as additional metadata solves the problem

    src/main/resources/META-INF/native-image/org.hibernate.orm/hibernate-core-additional-hints/reflect-config.json

    [
      {
        "name": "org.hibernate.persister.entity.JoinedSubclassEntityPersister",
        "queryAllDeclaredMethods": true,
        "condition": {
          "typeReachable": "org.hibernate.jpa.HibernatePersistenceProvider"
        },
        "methods": [
          {
            "name": "<init>",
            "parameterTypes": [
              "org.hibernate.mapping.PersistentClass",
              "org.hibernate.cache.spi.access.EntityDataAccess",
              "org.hibernate.cache.spi.access.NaturalIdDataAccess",
              "org.hibernate.persister.spi.PersisterCreationContext"
            ]
          },
          {
            "name": "<init>",
            "parameterTypes": [
              "org.hibernate.mapping.PersistentClass",
              "org.hibernate.cache.spi.access.EntityDataAccess",
              "org.hibernate.cache.spi.access.NaturalIdDataAccess",
              "org.hibernate.metamodel.spi.RuntimeModelCreationContext"
            ]
          }
        ]
      }
    ]
    
    

    I also opened https://github.com/oracle/graalvm-reachability-metadata/issues/589