gradle / gradle

Adaptable, fast automation for all
https://gradle.org
Apache License 2.0
16.68k stars 4.66k forks source link

Gradle module inference for non-modular apps breaks service loader for modular service architecture #24270

Open pedrolamarao opened 1 year ago

pedrolamarao commented 1 year ago

This simple project should respond to ./gradlew run with Hello World!. Instead, it raises NoSuchElementException.

https://github.com/pedrolamarao/gradle-module-path-decision

The cause is Gradle's decision to put api and impl in the class path instead of the module path. Gradle seems to make this decision based on the fact that app is not a module.

This decision breaks the service loader mechanism. impl declares it's provided services in its module definition. It is meant to be put in the module path, not the class path.

One may be tempted to avoid this problem by redeclaring impl 's services in META-INF/services. This way, when impl be put in the class path, the service loader is satisfied.

However, api module designers intended for the spi package to have restricted access to impl only. Allowing api and impl in the class path makes this restriction meaningless. To enforce this restriction, api and impl must require the module path.

This is just a contrived example. In the real case I was working with, there should be a closed set of N providers for a certain service. The user must not be able to insert providers in that set.

Currently, one cannot apply this kind of architecture with non-modular Gradle applications.

ov7a commented 1 year ago

Why can't you make your java app modular? If you do this, inference from Gradle should work.

pedrolamarao commented 1 year ago

Why can't you make your java app modular? If you do this, inference from Gradle should work.

I don`t develop applications, I develop components which my clients integrate into their applications.

ljacomet commented 1 year ago

Thank you for providing a valid reproducer.

The issue is in the backlog of the relevant team but the existence of a workaround makes it non-critical so it might take a while before a fix is made.


You might be able to tell Gradle to infer module path by calling java.modularity.inferModulePath = true (call set for Kotlin DSL without assignment operator)

pedrolamarao commented 1 year ago

I have updated the reproducer with 1) explicit inferModulePath = true, 2) Gradle 8.1-rc-1. Doing this did not change the outcome.