Implicit dependeny to subproject in multi module project

Hello Gradle community!

We provide an open source library that can be used as a starter for microservice development.

When upgrading to Gradle 8 the build fails with a lot of error messages of the following type:

A problem was found with the configuration of task ':sda-commons-server-auth-testing:compileTestJava' (type 'JavaCompile').
  - Gradle detected a problem with the following location: '/Users/christophercudennec/code/sda-se/sda-dropwizard-commons/sda-commons-server-auth/build/classes/java/main'.
    
    Reason: Task ':sda-commons-server-auth-testing:compileTestJava' uses this output of task ':sda-commons-server-auth:processResources' without declaring an explicit or implicit dependency. This can lead to incorrect results being produced, depending on what order the tasks are executed.
    
    Possible solutions:
      1. Declare task ':sda-commons-server-auth:processResources' as an input of ':sda-commons-server-auth-testing:compileTestJava'.
      2. Declare an explicit dependency on ':sda-commons-server-auth:processResources' from ':sda-commons-server-auth-testing:compileTestJava' using Task#dependsOn.
      3. Declare an explicit dependency on ':sda-commons-server-auth:processResources' from ':sda-commons-server-auth-testing:compileTestJava' using Task#mustRunAfter.
    
    Please refer to https://docs.gradle.org/8.1.1/userguide/validation_problems.html#implicit_dependency for more details about this problem.

I don’t really understand the point because the error message complains about modules that are defined as project dependencies. See the following dependency section in our module’s build.gradle:

dependencies {
  api project(':sda-commons-server-dropwizard')
  api project(':sda-commons-server-testing')
  api project(':sda-commons-server-auth')
  api 'com.auth0:java-jwt'
  api project(':sda-commons-client-jersey-wiremock-testing')

  api('org.apache.commons:commons-lang3')

  testImplementation project(':sda-commons-server-openapi')

  testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
}

I don’t expect the error messages “implicit dependency” in this case. Am I right?
Can you help me find out the cause of the problem?

Thanks a lot!

Christopher

1 Like

Where can it be seen?
If I try to open the major-gradle branch in IJ, it complains that you have an unresolved version conflict for antlr4-runtime.
And if I try to just execute the :sda-commons-server-auth-testing:compileTestJava task it complains that it cannot find some libraries needed by the wiremock project.

Hej @Vampire !

Thanks for taking the time to look into it! :sunflower:

I only tested it locally yesterday. I pushed the changes and created a PR that you can look into.

Here’s a pipeline run that contains the described errors.

Cheers,

Christopher

Well, a bit hard to say as your build is not nicely readable as you use bad-practices like subprojects { ... } and so on, so it is pretty unclear where what is configured, which is just one point of why subprojects { ... } and alike are bad.

But the error is definitely true.
If you execute gradle :sda-commons-server-auth-testing:compileTestJava no error happens and it builds, but :sda-commons-server-auth:processResources is not run.
If you execute gradle :sda-commons-server-auth:processResources :sda-commons-server-auth-testing:compileTestJava both tasks run and the error is displayed.

So somehow you configured the latter to use outputs of the former without having a proper dependency. And following the suggested solutions is usually just symptom treatment, but not an appropriate solution btw.

You configured output.resourcesDir = output.classesDirs.singleFile which is a very bad idea.
With that you configure tasks with overlapping outputs which has many problems and should be avoided as hell.
With that innocent looking configuration you for example configured the processResources and compileJava tasks to both have sda-commons-server-auth\build\classes\java\main as output directory.

While this has quite some other problems, your concrete error case now sda-commons-server-auth-testing:compileTestJava needs the class files of its dependency sda-commons-server-auth which causes it to also automatically have a dependency on the javaCompile task. But it does not have a dependency on the processResources task. But as that task also has the output directory, it now complains.

Well, a bit hard to say as your build is not nicely readable as you use bad-practices like subprojects { ... } and so on, so it is pretty unclear where what is configured, which is just one point of why subprojects { ... } and alike are bad.

I’ve also read that the subprojects approach is not recommended anymore. At the moment we still use it because we feel it’s easier to maintain than to spread the logic among different files. But I guess that’s probably only true for someone who’s worked with the project a lot :smiley: Thanks for pointing it out!

So somehow you configured the latter to use outputs of the former without having a proper dependency. And following the suggested solutions is usually just symptom treatment, but not an appropriate solution btw.

That’s why I came here. I had the same impression. :smiley:

You configured output.resourcesDir = output.classesDirs.singleFile which is a very bad idea.
With that you configure tasks with overlapping outputs which has many problems and should be avoided as hell.

I try to find a reason why this was configured in the first place. This is a very good explanation why we got the “implicit dependency” message. Thanks for spotting it! :sunflower:

I removed that part of the Gradle setup and was able to build my module! Waiting for the complete build.

At the moment we still use it because we feel it’s easier to maintain than to spread the logic among different files

While it might be cleaner to spread the logic to multiple convention plugins so that you can targetedly apply those and usually it is also easier to maintain and read, you can also put all this shared logic in one convention plugin that you then apply everywhere and that behaves differently depending on where it is applied.

Yes, subproject { ... } and some other things are discouraged now and should not be used. The introduce project coupling, making more sophisticated features that are there or yet to come like configure on demand, or project isolation for faster IDE sync impossible. Besides that they usually make the builds harder to understand and harder to maintain.

2 Likes

Thanks again for looking into the issue! It saved us a lot of time. :sunflower:

Funny note in the end:
I found out that we had the sourceSets configuration because of our Weld modules.
Seems like you also ran into that problem a couple of years ago :joy:

Cheers,

Christopher

Yeah, but that information is oooold. :smiley:
I think now I just don’t need the beans.xml anymore by configuring Weld appropriately or something like that, don’t have in in mind.