I have been trying to solve this implicit/explicit dependency warning that started after Gradle 7.4 upgrade (from Gradle 6).
I was able to fix it, but I thought I should share it here if anyone has more information about this and to share.
In summary, I created a plugin to be used with Java projects and one of its features is to - behind the scenes - add download a library - jar - and rename it to strip the version number and bundle it in the project’s fat jar.
I have included a stripped down version of my plugin and used Google gson as an example of a jar in this post for simplicity
The warning was caused by this line project.getDependencies().add(“compile”, fromTree) which is in the code snippet below and I can repro with it, but the warning will disappear if this line is replaced by project.getDependencies().add(“compile”, task.getOutputs().getFiles().getAsFileTree())
Below is the whole class code for this example
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import org.apache.commons.lang3.StringUtils;
import org.gradle.api.Action;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.file.FileTree;
import org.gradle.api.logging.Logger;
import org.gradle.api.tasks.TaskContainer;
import org.gradle.api.tasks.TaskProvider;
import java.nio.file.Paths;
import java.util.Objects;
/**
* Plugin used to ...
*/
public class MyGradlePackagePlugin implements Plugin<Project> {
public static final String JAR_NAME = "gson.jar";
public static final String ADD_DEPENDENCY = "addMyDependency";
@Override
public void apply(final Project project) {
final Logger logger = project.getLogger();
Objects.requireNonNull(project, "project cannot be null.");
final MyGradlePackagePluginExtension ext = project.getExtensions().create(
"mygradleplugin", MyGradlePackagePluginExtension.class);
final Configuration myconfig =
project.getConfigurations().create("addDependencyPlugin").setTransitive(false);
project.afterEvaluate(p -> {
myconfig.getDependencies().add(project.getDependencies().create(ImmutableMap.of(
"group", "com.google.code.gson",
"name", "gson",
"version", "2.9.0"
)));
});
final TaskProvider<Task> addDependency = project.getTasks().
register(ADD_DEPENDENCY, Task.class, task -> {
final String destinationDir = StringUtils.isBlank(ext.getCopyToDir())
? project.getBuildDir().toPath().resolve("libs").toString() :
ext.getCopyToDir();
final FileTree fromTree = project.fileTree(destinationDir,
tree -> tree.include("gson.jar"));
task.getOutputs().file(Paths.get(destinationDir).resolve(JAR_NAME));
//noinspection Convert2Lambda
task.doLast(new Action<Task>() {
@Override
public void execute(final Task task) {
project.getLogger().info("Copying jar from: " + myconfig.getAsPath() +
" into " + destinationDir);
project.copy(copy -> {
copy.from(myconfig)
.into(destinationDir)
.rename((name) -> JAR_NAME);
});
}
});
// To fix the execution optimization issue, we had to use task.getOutputs()....
// project.getDependencies().add("compile", task.getOutputs().getFiles().getAsFileTree());
// This line causes warning
// Execution optimizations have been disabled for task '***' to ensure correctness due to the
// following reasons:
// - Gradle detected a problem with the following location:
// '.......gson.jar'. Reason: Task '****' uses this output of task ':addMyDependency' 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.
project.getDependencies().add("compile", fromTree);
});
project.afterEvaluate(p -> {
// Had to keep this dependency, otherwise jar in not bundled in Gradle7 projects
// When complete migration to Gradle 7 is done, we should revisit this
final ImmutableList<String> gradleTasks = ImmutableList.of("assemble");
final TaskContainer tasks = project.getTasks();
// add the new assemble task dependency
tasks.stream().filter(task -> gradleTasks.contains(task.getName())).forEach(
task -> task.dependsOn(addDependency));
});
}
}