Hibernate ORM does not detect services provided by libraries in the module path

Description

Classifying this as a bug because it effectively prevents from using Hibernate ORM in a modular environment beyond the very simple use cases, even though we did some work to make Hibernate ORM usable, as an automatic module.

In short, when a user deploys an application in the module path, they have no choice but to only ever use modules. As a result, they will use Hibernate ORM as an automatic module, and more importantly they will also use other libraries, such as Hibernate Search, as automatic modules. They simply cannot leave those in the classpath: they couldn't access them.

The problem is, as soon as other libraries are in the module path, Hibernate ORM seems unable to detect their declared services.

I investigated a bit, and the problem is not that automatic modules cannot declare services or use services from other modules (that works just fine), it's really only Hibernate ORM that fails to load the modules. You can see this live in this reproducer: https://github.com/yrodiere/java-module-sandbox/

Just clone it, set JDK11 as your default JDK, and run mvn clean install.

You'll see this in the logs:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 [exec] ====================================================== [exec] STARTING EXECUTION [exec] ====================================================== [exec] [exec] [exec] module { name: org.hibernate.search.mapper.orm@6.0.0-SNAPSHOT, [mandated java.base], provides: [org.hibernate.service.spi.ServiceContributor with [org.hibernate.search.mapper.orm.impl.HibernateSearchContextServiceContributor], org.hibernate.integrator.spi.Integrator with [org.hibernate.search.mapper.orm.bootstrap.impl.HibernateSearchIntegrator]] } [exec] module { name: org.hibernate.search.engine@6.0.0-SNAPSHOT, [mandated java.base] } [exec] module { name: org.hibernate.sandbox.java.service.consumer@1.0-SNAPSHOT, [mandated java.base] } [exec] module { name: org.hibernate.orm.core@5.4.2.Final, [mandated java.base], provides: [javax.persistence.spi.PersistenceProvider with [org.hibernate.jpa.HibernatePersistenceProvider]] } [exec] module { name: org.hibernate.search.util.common@6.0.0-SNAPSHOT, [mandated java.base] } [exec] module { name: org.hibernate.search.mapper.pojo@6.0.0-SNAPSHOT, [mandated java.base] } [exec] module { name: org.hibernate.commons.annotations@5.1.0.Final, [mandated java.base] } [exec] module { name: org.hibernate.sandbox.java.main@1.0-SNAPSHOT, [org.hibernate.orm.core, org.hibernate.search.mapper.orm, mandated java.base (@11.0.3), net.bytebuddy, java.xml.bind, java.sql (@11.0.3), java.naming (@11.0.3), org.hibernate.sandbox.java.service.consumer, java.persistence], exports: [org.hibernate.sandbox.java.main] } [exec] module { name: org.hibernate.sandbox.java.service.provider@1.0-SNAPSHOT, [mandated java.base], provides: [org.hibernate.sandbox.java.service.consumer.MyService with [org.hibernate.sandbox.java.service.provider.MyServiceImpl]] } [exec] [exec] [exec] ===== RESULT: [exec] My services loaded from consumer module (automatic module without module-info.java): [exec] [org.hibernate.sandbox.java.service.provider.MyServiceImpl] [exec] [exec] [exec] ===== RESULT: [exec] Hibernate ORM services loaded from consumer module (automatic module without module-info.java): [exec] [org.hibernate.search.mapper.orm.bootstrap.impl.HibernateSearchIntegrator@5f3a4b84, org.hibernate.search.mapper.orm.impl.HibernateSearchContextServiceContributor@27f723] [exec] [exec] [exec] Booting Hibernate ORM service registry... [exec] May 23, 2019 10:52:58 AM org.hibernate.Version logVersion [exec] INFO: HHH000412: Hibernate Core {[WORKING]} [exec] Finished booting Hibernate ORM service registry. [exec] [exec] [exec] ===== RESULT: [exec] Hibernate services loaded from Hibernate ORM module by bootstrapping a service registry only: [exec] [org.hibernate.cfg.beanvalidation.BeanValidationIntegrator@22eeefeb, org.hibernate.secure.spi.JaccIntegrator@64485a47, org.hibernate.cache.internal.CollectionCacheInvalidator@77846d2c] [exec] [exec] [exec] Booting Hibernate ORM session factory... [exec] May 23, 2019 10:52:58 AM org.hibernate.annotations.common.reflection.java.JavaReflectionManager <clinit> [exec] INFO: HCANN000001: Hibernate Commons Annotations {5.1.0.Final} [exec] May 23, 2019 10:52:58 AM org.hibernate.engine.jdbc.connections.internal.ConnectionProviderInitiator initiateService [exec] WARN: HHH000181: No appropriate connection provider encountered, assuming application will be supplying connections [exec] May 23, 2019 10:52:58 AM org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator initiateService [exec] WARN: HHH000342: Could not obtain connection to query metadata : The application must supply JDBC connections [exec] May 23, 2019 10:52:58 AM org.hibernate.dialect.Dialect <init> [exec] INFO: HHH000400: Using dialect: org.hibernate.dialect.H2Dialect [exec] May 23, 2019 10:52:58 AM org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformInitiator initiateService [exec] INFO: HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform] [exec] Finished booting Hibernate ORM session factory. [exec] [exec] [exec] ===== RESULT: [exec] Hibernate services loaded from Hibernate ORM module by bootstrapping a whole session factory: [exec] [org.hibernate.cfg.beanvalidation.BeanValidationIntegrator@36916eb0, org.hibernate.secure.spi.JaccIntegrator@7bab3f1a, org.hibernate.cache.internal.CollectionCacheInvalidator@437da279] [exec] [exec] [exec] Booting Hibernate ORM entity manager factory... [exec] May 23, 2019 10:52:58 AM org.hibernate.jpa.internal.util.LogHelper logPersistenceUnitInformation [exec] INFO: HHH000204: Processing PersistenceUnitInfo [name: primaryPU] [exec] May 23, 2019 10:52:58 AM org.hibernate.engine.jdbc.connections.internal.ConnectionProviderInitiator initiateService [exec] WARN: HHH000181: No appropriate connection provider encountered, assuming application will be supplying connections [exec] May 23, 2019 10:52:58 AM org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator initiateService [exec] WARN: HHH000342: Could not obtain connection to query metadata : The application must supply JDBC connections [exec] May 23, 2019 10:52:58 AM org.hibernate.dialect.Dialect <init> [exec] INFO: HHH000400: Using dialect: org.hibernate.dialect.H2Dialect [exec] May 23, 2019 10:52:58 AM org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformInitiator initiateService [exec] INFO: HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform] [exec] Finished booting Hibernate ORM entity manager factory. [exec] [exec] [exec] ===== RESULT: [exec] Hibernate services loaded from Hibernate ORM module by bootstrapping a whole entity manager factory: [exec] [org.hibernate.cfg.beanvalidation.BeanValidationIntegrator@51650883, org.hibernate.secure.spi.JaccIntegrator@6c4f9535, org.hibernate.cache.internal.CollectionCacheInvalidator@5bd1ceca] [exec] [exec] [exec] ====================================================== [exec] ENDING EXECUTION [exec] ======================================================

What's important here are the information below the "RESULT" lines:

  1. The first one demonstrates that an automatic module can load services provided by another automatic module. I created custom modules just for that.

  2. The second one demonstrates that an automatic module can load services provided by Hibernate Search used as an automatic module.

  3. The third, fourth and fifth ones demonstrate that Hibernate ORM does not see Hibernate Search services when booted as an automatic module. Interestingly, libraries that stay in the classpath (because the application does not use them directly) have their services correctly detected.

I think the root cause of the problem may have something to do with how ORM uses an aggregated classloader.

Indeed, I've also experienced NoClassDefFoundError in my modular application, and I had to declare dependencies from my application to other modules such as java.xml.bind, even though my application doesn't use those: only Hibernate ORM does. There is something fishy here...

Related:

Environment

None

Status

Assignee

Yoann Rodière

Reporter

Yoann Rodière

Fix versions

Labels

None

backPortable

None

Suitable for new contributors

None

Requires Release Note

None

backportDecision

None

Components

Affects versions

5.4.2

Priority

Major