Skip to content

Unable to require module when plugin is used #12

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
C-Otto opened this issue Jan 24, 2021 · 4 comments
Closed

Unable to require module when plugin is used #12

C-Otto opened this issue Jan 24, 2021 · 4 comments

Comments

@C-Otto
Copy link

C-Otto commented Jan 24, 2021

I'm using Java 14 with Gradle 6.8.1. I have two projects, cli and backend. The CLI is a Spring Boot application, whereas backend is a Java library (which also uses Spring Boot, with jar enabled and bootJar disabled). I'm using JMPS to include backend from within cli.

As soon as I add id 'de.jjohannes.extra-java-module-info' version '0.5' to the plugins section of my subproject backend, I can't build the consuming project cli anymore, as shown below. Sadly, I also need to use the plugin, as I have to use a library in backend which does not define a module descriptor (OpenFeign/feign#1357 and spring-cloud/spring-cloud-openfeign#469).

I also use your plugin in cli for another library without a module descriptor (spring-projects/spring-shell#315).

$ ./gradlew build

FAILURE: Build failed with an exception.

* What went wrong:
Could not determine the dependencies of task ':cli:bootJar'.
> Could not resolve all task dependencies for configuration ':cli:runtimeClasspath'.
   > Could not resolve project :backend.
     Required by:
         project :cli
      > The consumer was configured to find a runtime of a library compatible with Java 14, packaged as a jar, and its dependencies declared externally, as well as attribute 'javaModule' with value 'true'. However we cannot choose between the following variants of project :backend:
          - productionRuntimeClasspath
          - runtimeElements
        All of them match the consumer attributes:
          - Variant 'productionRuntimeClasspath' capability de.cotto:backend:0.0.1-SNAPSHOT declares a runtime of a component, packaged as a jar, and its dependencies declared externally, as well as attribute 'javaModule' with value 'true':
              - Unmatched attributes:
                  - Doesn't say anything about its component category (required a library)
                  - Doesn't say anything about its target Java version (required compatibility with Java 14)
          - Variant 'runtimeElements' capability de.cotto:backend:0.0.1-SNAPSHOT declares a runtime of a library compatible with Java 14, packaged as a jar, and its dependencies declared externally:
              - Unmatched attribute:
                  - Doesn't say anything about javaModule (required 'true')
        The following variants were also considered but didn't match the requested attributes:
          - Variant 'apiElements' capability de.cotto:backend:0.0.1-SNAPSHOT declares a library compatible with Java 14, packaged as a jar, and its dependencies declared externally:
              - Incompatible because this component declares an API of a component and the consumer needed a runtime of a component
              - Other compatible attribute:
                  - Doesn't say anything about javaModule (required 'true')

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 541ms
@jjohannes
Copy link
Member

@C-Otto I think this is an effect not specific to this plugin but a result of combining plugins that do not setup everything "well enough" for variant-aware dependency resolution which was not supported in earlier Gradle version.

In this case productionRuntimeClasspath, added by the spring boot plugin, is confusing the resolution. It thinks it is something that might match. It works coincidentally when you do not use this plugin (which adds the javaModule attribute) because Gradle tries to make a decision based on the number of attributes that it can/cannot match. And if there is a perfect match, it would prefer it. Which covers most cases where things are not well enough defined.

In this case, I think the spring boot plugin should set productionRuntimeClasspath.canBeConsumed = false. Then it won't interfere with the resolution anymore. You can fix that in your build by adding this line:

// Groovy DSL build.gradle in your 'backend' project:
configuration.productionRuntimeClasspath.canBeConsumed = false

I haven't been able to reproduce this myself. Which Spring Boot version are you using? Maybe it works with newer versions.

@C-Otto
Copy link
Author

C-Otto commented Feb 24, 2021

Thanks for the explanation, I'll try to understand it. I'm using Spring Boot configured as follows:

implementation 'org.springframework.boot:spring-boot-gradle-plugin:2.4.2'
implementation 'io.spring.gradle:dependency-management-plugin:1.0.11.RELEASE'

I understand that Spring Boot does quite a lot of stuff that isn't Gradle-y (spring-projects/spring-boot#25126, gradle/gradle#16059 for a recent example), which is rather unfortunate. Could you open an issue in the Spring Boot project? I'm not comfortable enough with Gradle internals, and I'd like to avoid pointing fingers without a good technical explanation.

@iherasymenko
Copy link
Contributor

iherasymenko commented Feb 24, 2021

@C-Otto those are Gradle plugins and you should be including them in the plugins section of the build.gradle DSL. From what I see, you tried to include them as project dependencies. Moreover, the former plugin already includes the latter plugin, so you have to specify just one of the plugins depending on your use case.

If you are interested in modularizing Spring Boot apps, you may find this PR useful. However, be ready to face more issues than you currently have with your configuration ;-)

@jjohannes
Copy link
Member

@C-Otto I am happy to open a Spring Boot issue, but I need to reproduce the problem to fully understand what it is. Would you be able to share a complete small project reproducing what you are seeing?

Does adding this to the build file of backend solve the problem for you?

configuration.productionRuntimeClasspath.canBeConsumed = false

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants