| When running an application in the modulepath, this application will declare dependencies to Hibernate Search and Hibernate ORM in its module-info.java. As a result, both Hibernate Search and Hibernate ORM will be automatically promoted to (automatic) modules and put in the modulepath. Since Hibernate Search and ORM are now modules, unfortunately they have to comply with all the module rules, even if they are just "automatic modules". This means no split packages (so far so good), but more crucially this means services must be declared in a module-info.java... Indeed, the service loader completely ignores META-INF/services when the service class is defined in a module; see java.util.ServiceLoader.LazyClassPathLookupIterator#hasNextService:
if (clazz.getModule().isNamed()) {
continue;
}
So only the other services iterator, ModuleServicesLookupIterator, is effective when looking for service providers defined in modules. Services providing and consumption in modules requires both the provider and user to declare the service:
- The service provider must add a provides <service interface> with <service implementation class>; clause to its module-info.java
- The service consumer must add a uses <service interface>; clause to its module-info.java.
Fortunately, provides directives are automatically added to the module descriptor of automatic modules based on service files from META-INF/services/*, as explained here. I checked that in debug mode: it works perfectly in the case of Hibernate Search. Unfortunately, it seems we really cannot use a service from another module in an automatic module:
- On contrary to provides directives, uses directives are not automatically generated for automatic modules (how could they?)
- Automatic module are assumed to implicitly require every other module by default and expose implicitly all of their packages (this page tells you that much, though I couldn't find a more up-to-date source). However, they do not seem to use every service. This SO answer states "An automatic module is assumed allowed to use all services." but that doesn't seem to be true. Automatic modules can implicitly use all services from the classpath only.
- There are many options to add various directives to modules when starting the JVM: -
add-opens, -add-exports, add-reads, ... but no -add-uses.
- There are ways to add uses directives to a module at runtime, dynamically, from the module itself. But it is explicitly defined as a no-op for automatic modules. See java.lang.Module#addUses: "This method is a no-op when invoked on an unnamed module or an automatic module"
- I could not find out why, but java.lang.module.ModuleDescriptor.Builder#uses, the API to add a uses directive when building a module descriptor dynamically, throws an exception for automatic modules: throw new IllegalStateException("Automatic modules can not declare service dependences").
It really looks like, in order to solve this problem, we will have to add a module-info.java to Hibernate ORM, so that it correctly declares uses directives. Going further, HSEARCH-3274 In Progress (the addition of a module-info.java to Hibernate Search) may also be necessary in order to make consumption of services from Hibernate Search work correctly (e.g. for ElasticsearchBeanConfigurer and such). |