Side-effect-only task is causing many build warnings and disabling optimizations

Hi folks,

I have a multi-subproject Gradle build. Several of my subprojects generate wars and then explode them on disk just so that my Docker build can find the files it needs later, after the Gradle build finishes.

I’m exploding the wars using this snippet I copied off the web somewhere:

// This builds the server as a WAR file, though we don't actually use it.
// The important thing is the exploded WAR, from which the Dockerfile copies in
// all the app server's dependency jars.
task explodedWar(type: Copy) {
    into "$buildDir/libs"
    with war
}
war.finalizedBy "explodedWar"

Nothing in my build actually uses the output of this task, or at least, I don’t think it’s supposed to.

Since upgrading to Gradle 7.x, I’ve been getting lots of build warnings of the form:

  - Gradle detected a problem with the following location: '/Users/me/myapp/server/build/libs/myapp-server-1.0-SNAPSHOT.jar'. Reason: Task ':myapp-content:distZip' uses this output of task ':myapp-server:explodedWar' without declaring an explicit or implicit dependency. This can lead to incorrect results being produced, depending on what order the tasks are executed. Please refer to https://docs.gradle.org/7.4/userguide/validation_problems.html#implicit_dependency for more details about this problem.

Basically almost every task in every build file is generating this warning.

I just want the war to be generated and unpacked at the end of my build. What’s the best way to fix this?

Hi Steve,

looking at the snippet, is seems that the explodedWar puts all the files for the War directly in the build/libs folder. This folder is also used by other artifacts produced by Gradle, and that is why you have the warning.

Does the warning go away when you use build/libs/exploded or maybe even build/explodedWar as a directory for exploding the war file?

Cheers,
Stefan

That fixed it! Thanks so much.

Steve

Two more things to note:

  • As you are using Copy you might have stale files in the output directory as it just copies in to whatever is already present. If you want an exact result you should use Sync instead.
  • You are not actually exploding the built war. Your explode task can actually be executed without executing the war task if you don’t need the war. The with war reuses the implicit CopySpec of the war task that defines which files to copy from where into the war, to copy (or sync) those exact files to the target directory without the detour through the war. That means you for example will not get the manifest file, …

Thanks for noticing that. I’ve changed it to use Sync. Should I remove the “with war” line? I don’t need the war.

No, you misunderstood.
The war task has a recipe “take file X and store it at Y in the war, the file Z and store it at W in the war”. The with war reuses this information but it simply takes the files from the original locations. It does not build the war and then explodes it.