October 25, 2024
Chicago 12, Melborne City, USA
java

Can't run latest Hibernate (7.0.0.Beta1) in a module environment


The problem

I’m having trouble trying to make Hibernate run in a project that have modules. I am trying to modernize an old tool that uses and old version of Hibernate with javax-based JPA and I am trying to migrate it to a newer version and make it jakarta-based.

Long story short, it fails with ExceptionInInitializerError when trying to instantiate the HibernatePersistenceProvider class due to some module problem when handling JBoss Logging. The tool use the HibernatePersistenceProvider to call the createContainerEntityManagerFactory method.

In order to isolate the problem, I built a MCVE.

MCVE

I’m using Gradle 8.10.2 and Java 23. All the other package versions are in the gradle.build file.

This is the build.gradle file:

plugins {
    id("java-library")
    id("project-report")
}

description = "MCVE for a problem in Hibernate"
group = "com.example"
version = "1.0"

def artifactName = "com.example"
def moduleName = "com.example"

def versionApiguardian = "1.1.2"
def versionHibernate   = "7.0.0.Beta1"
def versionJakartaAnno = "3.0.0"
def versionJakartaCdi  = "4.1.0"
def versionJakartaEl   = "6.0.1"
def versionJakartaInj  = "2.0.1"
def versionJakartaInt  = "2.2.0"
def versionJakartaJpa  = "3.2.0"
def versionJakartaJta  = "2.0.1"
def versionJBossLog    = "3.6.1.Final"
def versionJunit       = "5.11.2"
def versionJunitPlatf  = "1.11.2"

dependencies {

    // Jakarta, JPA and friends.
    testImplementation(group: "jakarta.annotation" , name: "jakarta.annotation-api"       , version: versionJakartaAnno)
    testImplementation(group: "jakarta.enterprise" , name: "jakarta.enterprise.cdi-api"   , version: versionJakartaCdi )
    testImplementation(group: "jakarta.enterprise" , name: "jakarta.enterprise.lang-model", version: versionJakartaCdi )
    testImplementation(group: "jakarta.persistence", name: "jakarta.persistence-api"      , version: versionJakartaJpa )
    testImplementation(group: "jakarta.transaction", name: "jakarta.transaction-api"      , version: versionJakartaJta )
    testImplementation(group: "jakarta.inject"     , name: "jakarta.inject-api"           , version: versionJakartaInj )
    testImplementation(group: "jakarta.interceptor", name: "jakarta.interceptor-api"      , version: versionJakartaInt )
    testImplementation(group: "jakarta.el"         , name: "jakarta.el-api"               , version: versionJakartaEl  )

    // JUnit.
    testImplementation(group: "org.junit.platform", name: "junit-platform-launcher", version: versionJunitPlatf )
    testImplementation(group: "org.junit.jupiter" , name: "junit-jupiter-api"      , version: versionJunit      )
    testImplementation(group: "org.junit.jupiter" , name: "junit-jupiter-params"   , version: versionJunit      )
    testImplementation(group: "org.junit.jupiter" , name: "junit-jupiter-engine"   , version: versionJunit      )
    testImplementation(group: "org.apiguardian"   , name: "apiguardian-api"        , version: versionApiguardian)

    // Hibernate.
    testImplementation(group: "org.hibernate.orm", name: "hibernate-core", version: versionHibernate)

    // JBoss Logging.
    testImplementation(group: "org.jboss.logging", name: "jboss-logging", version: versionJBossLog)
}

repositories {
    mavenLocal()
    mavenCentral()
    gradlePluginPortal()
}

tasks.withType(JavaCompile) {
    options.encoding = "UTF-8"
    options.debug = true
    options.fork = true
    options.compilerArgs << "-parameters"
    doFirst {
        options.compilerArgs += [
            "--module-path", classpath.asPath
        ]
        classpath = files()
    }
}

test {
    useJUnitPlatform()
    defaultCharacterEncoding = "UTF-8"
    testLogging.showStandardStreams = true
}

And, here is the /src/test/java/module-info.java file:

open module com.example {
    requires org.hibernate.orm.core;
    requires org.junit.jupiter.api;
}

And here is the /src/test/java/com/example/SomeTest.java file:

package com.example;

import org.hibernate.jpa.HibernatePersistenceProvider;
import org.junit.jupiter.api.Test;

public class SomeTest {
    @Test
    public void testIt() {
        new HibernatePersistenceProvider();
    }
}

Running that with this command line:

gradle build --info

Will produce this inside all the output:

SomeTest > testIt() FAILED
    java.lang.ExceptionInInitializerError
        at com.example/com.example.SomeTest.testIt(SomeTest.java:9)

        Caused by:
        java.lang.IllegalArgumentException: This library does not have private access to interface org.hibernate.internal.EntityManagerMessageLogger
            at org.jboss.logging@3.6.1.Final/org.jboss.logging.Logger.getMessageLogger(Logger.java:2572)
            at org.jboss.logging@3.6.1.Final/org.jboss.logging.Logger.getMessageLogger(Logger.java:2552)
            at org.hibernate.orm.core@7.0.0.Beta1/org.hibernate.internal.HEMLogging.messageLogger(HEMLogging.java:28)
            at org.hibernate.orm.core@7.0.0.Beta1/org.hibernate.internal.HEMLogging.messageLogger(HEMLogging.java:24)
            at org.hibernate.orm.core@7.0.0.Beta1/org.hibernate.jpa.HibernatePersistenceProvider.<clinit>(HibernatePersistenceProvider.java:42)
            ... 1 more

1 test completed, 1 failed

Trying to downgrade JBoss-Logging to 3.5.0.Final (which is the version declared as a dependency for Hibernate 7.0.0.Beta1 accordingly to this) will give a different error instead:

SomeTest > testIt() FAILED
    java.lang.IllegalAccessError: superclass access check failed: class org.jboss.logging.JBossLogRecord (in module org.jboss.logging) cannot access class java.util.logging.LogRecord (in module java.logging) because module org.jboss.logging does not read module java.logging
        at java.base/java.lang.ClassLoader.defineClass1(Native Method)
        at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1026)
        at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1103)
        at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:182)
        at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:821)
        at java.base/jdk.internal.loader.BuiltinClassLoader.findClassInModuleOrNull(BuiltinClassLoader.java:741)
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:665)
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:639)
        at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:528)
        at org.jboss.logging@3.5.0.Final/org.jboss.logging.JDKLoggerProvider.getLogger(JDKLoggerProvider.java:29)
        at org.jboss.logging@3.5.0.Final/org.jboss.logging.LoggerProviders.logProvider(LoggerProviders.java:150)
        at org.jboss.logging@3.5.0.Final/org.jboss.logging.LoggerProviders.tryJDK(LoggerProviders.java:106)
        at org.jboss.logging@3.5.0.Final/org.jboss.logging.LoggerProviders.findProvider(LoggerProviders.java:101)
        at org.jboss.logging@3.5.0.Final/org.jboss.logging.LoggerProviders.find(LoggerProviders.java:32)
        at org.jboss.logging@3.5.0.Final/org.jboss.logging.LoggerProviders.<clinit>(LoggerProviders.java:29)
        at org.jboss.logging@3.5.0.Final/org.jboss.logging.Logger.getLogger(Logger.java:2465)
        at org.jboss.logging@3.5.0.Final/org.jboss.logging.Logger.doGetMessageLogger(Logger.java:2573)
        at org.jboss.logging@3.5.0.Final/org.jboss.logging.Logger.getMessageLogger(Logger.java:2530)
        at org.jboss.logging@3.5.0.Final/org.jboss.logging.Logger.getMessageLogger(Logger.java:2516)
        at org.hibernate.orm.core@7.0.0.Beta1/org.hibernate.internal.HEMLogging.messageLogger(HEMLogging.java:28)
        at org.hibernate.orm.core@7.0.0.Beta1/org.hibernate.internal.HEMLogging.messageLogger(HEMLogging.java:24)
        at org.hibernate.orm.core@7.0.0.Beta1/org.hibernate.jpa.HibernatePersistenceProvider.<clinit>(HibernatePersistenceProvider.java:42)
        at com.example/com.example.SomeTest.testIt(SomeTest.java:9)

1 test completed, 1 failed

The workaround

As a proof of concept, if I sacrifice modularity, remove the module-info.java file and comment out the doFirst block in the gradle.build file, it works!

However, I can’t really sacrifice modularity in my environment.

My questions

  • Maybe I should add something to the module-info.java file?
  • Or maybe I should change the version of some package?
  • Or perhaps add some --add-opens command line options somewhere in gradle.build?
  • Or should I avoid to ever directly instantiate HibernatePersistenceProvider and it was no more than an accident that this ever worked?
  • Is this a bug in Hibernate 7.0.0 Beta 1?

Or put simply:

  • What I am doing wrong?
  • How can I fix this?
  • Any ideas?

I tried a lot of things to fix this issue, and other than just throwing modularity out of the window, nothing worked so far.



You need to sign in to view this answers

Leave feedback about this

  • Quality
  • Price
  • Service

PROS

+
Add Field

CONS

+
Add Field
Choose Image
Choose Video