Providing artifacts (not jar) via DefaultDependencyArtifact in Gradle-Java-Plugin

plugins

(SL) #1

i have developed a custom gradle plugin under Gradle 4.2.1 that provides a Task, which copies Artifacts (not jar) from our local Nexus-Repo into my local Directory.
This worked fine under Gradle 4.2.1. Once i updated gradle to version 4.10 the plugin ran into this exception:
(i testet all version and found out, that this error occurs since gradle 4.4)

this behavior can be reproduced when switching vom gradle 4.2 to gradle 4.4

Does anyone have an idea, how to implement this dependencies in the plugin in the correct way?

Thanks for help

DefaultMutableVersionConstraint cannot be cast to org.gradle.api.internal.artifacts.VersionConstraintInternal

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':downloadArchives'.
> Could not resolve all dependencies for configuration ':fromRepository'.
   > org.gradle.api.internal.artifacts.dependencies.DefaultMutableVersionConstraint cannot be cast to org.gradle.api.internal.artifacts.VersionConstraintInternal

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

* Exception is:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':downloadArchives'.
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:100)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:70)
        at org.gradle.api.internal.tasks.execution.OutputDirectoryCreatingTaskExecuter.execute(OutputDirectoryCreatingTaskExecuter.java:51)
        at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:62)
        at org.gradle.api.internal.tasks.execution.ResolveTaskOutputCachingStateExecuter.execute(ResolveTaskOutputCachingStateExecuter.java:54)
        at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:60)
        at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:97)
        at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:87)
        at org.gradle.api.internal.tasks.execution.ResolveTaskArtifactStateTaskExecuter.execute(ResolveTaskArtifactStateTaskExecuter.java:52)
        at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:52)
        at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:54)
        at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
        at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:34)
        at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker$1.run(DefaultTaskGraphExecuter.java:248)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:336)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:328)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:199)
        at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:110)
        at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:241)
        at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:230)
        at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.processTask(DefaultTaskPlanExecutor.java:123)
        at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.access$200(DefaultTaskPlanExecutor.java:79)
        at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker$1.execute(DefaultTaskPlanExecutor.java:104)
        at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker$1.execute(DefaultTaskPlanExecutor.java:98)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionPlan.execute(DefaultTaskExecutionPlan.java:626)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionPlan.executeWithTask(DefaultTaskExecutionPlan.java:581)
        at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.run(DefaultTaskPlanExecutor.java:98)
        at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
        at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
        at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)

Code:

Task createDownloadArchives(Project project) {
        DefaultExternalModuleDependency moduleDependency = new DefaultExternalModuleDependency(project.getGroup().toString(), project.getName().toString(), project.getVersion().toString());
        moduleDependency.getArtifacts().add(new DefaultDependencyArtifact(project.getName().toString(), "zip", "zip", project.getName(), null));
        moduleDependency.getArtifacts().add(new DefaultDependencyArtifact(project.getName().toString(), "sh", "sh", project.getName(), null));
        moduleDependency.getArtifacts().add(new DefaultDependencyArtifact(project.getName().toString(), "txt", "txt", "readme", null));

        Project helperProject = ProjectBuilder.builder().withGradleUserHomeDir(new File(System.getProperty("java.io.tmpdir"))).withProjectDir(new File(System.getProperty("java.io.tmpdir"))).build();

        helperProject.getRepositories().maven(mavenArtifactRepository -> {
            try {
                mavenArtifactRepository.setUrl(new URI("http://localmavenrepo.local"));
            } catch (URISyntaxException e) {
                e.printStackTrace();
            }
        });

        Configuration fromRepo = helperProject.getConfigurations().create("fromRepository");
        fromRepo.getDependencies().add(moduleDependency);

        Task downloadArchives = project.getTasks().create("downloadArchives", DefaultTask.class, task -> {
            task.setGroup("Servertasks");
            task.doLast(t -> {
                fromRepo.getResolvedConfiguration().getResolvedArtifacts().forEach(resolvedArtifact -> {
                    if (resolvedArtifact.getName().equals(project.getName())) {
                        project.copy(spec -> {
                            spec.from(resolvedArtifact.getFile());
                            spec.into(project.getBuildDir() + "/fromRepository");
                        });
                    }
                });
            });
        });

        return downloadArchives;
    }

this code is equivalent to this groovy code:

version = "1.0.0"

configurations {
    fromRepository
}

dependencies {
    fromRepository (group: "xyz", name:"archive", version:version, ext: "zip" )
    fromRepository (group: "xyz", name:"archive", version:version, ext: "sh"  )
}

task buildComplete {
    
    group "custom_build"
    doLast {
        configurations.fromRepository.resolvedConfiguration.resolvedArtifacts.each { art ->
            copy {
                from art.file
                into "$buildDir"
            }
        }
    }
}

(Sterling Greene) #2

It’s not completely clear what you’re trying to do, but this is definitely overcomplicating things a bit. Your Groovy example is not doing the same thing as the Java one.

  • You should never need to create internal implementation classes (Default...) directly. There should always be a public API to create an instance if you need it. In this case, you want project.getDependencies().create(...). You can configure the artifacts as well without explicitly creating DefaultDependencyArtifact. You can see an example of this at the bottom of the Javadoc for the class here
  • ProjectBuilder is intended solely for creating unit tests. I’m not sure why you’re using it here.
  • I think you’re trying to only copy the direct dependencies and none of the transitive dependencies with the resolvedArtifact.getName().equals(project.getName()) check. You can just disable transitive dependencies for the configuration.
  • Your downloadArchives task could be/should be a Sync task, something like:
task downloadArchives(type: Sync) {
    from(configurations.fromRepository)
    into(new File(buildDir, "fromRepository"))
}

My suspicion is that this is hiding some other problem, so you could try at least replacing the direct instantiation of internal classes with the factory methods and see if that gets you working again.


(SL) #3

Thank you for your advice.
I think the String notation ( “group:name:version:classifier@extension” ) seems the right way to do this in java.
I will try this on monday.