Skip to content

Commit c583470

Browse files
committed
'requireAllDefinedDependencies' computes correct scopes
Before the 'transitive' scope was not correct (see removed comment in code). This let to different results depending for components that were direct and transitive dependencies.
1 parent 85f169f commit c583470

File tree

3 files changed

+149
-71
lines changed

3 files changed

+149
-71
lines changed

src/main/java/org/gradlex/javamodule/moduleinfo/ExtraJavaModuleInfoPlugin.java

Lines changed: 21 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,8 @@
2525
import org.gradle.api.artifacts.component.ComponentIdentifier;
2626
import org.gradle.api.artifacts.component.ModuleComponentIdentifier;
2727
import org.gradle.api.artifacts.dsl.DependencyHandler;
28-
import org.gradle.api.artifacts.result.DependencyResult;
2928
import org.gradle.api.artifacts.result.ResolvedArtifactResult;
3029
import org.gradle.api.artifacts.result.ResolvedComponentResult;
31-
import org.gradle.api.artifacts.result.ResolvedDependencyResult;
3230
import org.gradle.api.attributes.Attribute;
3331
import org.gradle.api.attributes.Category;
3432
import org.gradle.api.attributes.Usage;
@@ -60,10 +58,8 @@
6058
/**
6159
* Entry point of the plugin.
6260
*/
63-
@SuppressWarnings("unused")
6461
@NonNullApi
6562
public abstract class ExtraJavaModuleInfoPlugin implements Plugin<Project> {
66-
private static final Attribute<String> CATEGORY_ATTRIBUTE_UNTYPED = Attribute.of(CATEGORY_ATTRIBUTE.getName(), String.class);
6763

6864
@Override
6965
public void apply(Project project) {
@@ -193,57 +189,44 @@ private void registerTransform(String fileExtension, Project project, ExtraJavaM
193189
p.getMergeJarIds().set(artifacts.map(new IdExtractor()));
194190
p.getMergeJars().set(artifacts.map(new FileExtractor(project.getLayout())));
195191

196-
p.getCompileClasspathDependencies().set(project.provider(() ->
197-
toStringMap(sourceSets.stream().flatMap(s -> filteredResolutionResult(configurations.getByName(s.getCompileClasspathConfigurationName()), componentsOfInterest(extension))))));
198-
p.getRuntimeClasspathDependencies().set(project.provider(() ->
199-
toStringMap(sourceSets.stream().flatMap(s -> filteredResolutionResult(configurations.getByName(s.getRuntimeClasspathConfigurationName()), componentsOfInterest(extension))))));
200-
p.getAnnotationProcessorClasspathDependencies().set(project.provider(() ->
201-
toStringMap(sourceSets.stream().flatMap(s -> filteredResolutionResult(configurations.getByName(s.getAnnotationProcessorConfigurationName()), componentsOfInterest(extension))))));
192+
p.getRequiresFromMetadata().set(project.provider(() -> sourceSets.stream().flatMap(s -> Stream.of(
193+
s.getRuntimeClasspathConfigurationName(),
194+
s.getCompileClasspathConfigurationName(),
195+
s.getAnnotationProcessorConfigurationName()
196+
))
197+
.flatMap(resolvable -> existingComponentsOfInterest(configurations.getByName(resolvable), extension))
198+
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (k1, k2) -> k1)).entrySet().stream()
199+
.collect(Collectors.toMap(Map.Entry::getKey, c -> new PublishedMetadata(c.getKey(), c.getValue(), project)))
200+
));
202201
});
203202
t.getFrom().attribute(artifactType, fileExtension).attribute(javaModule, false);
204203
t.getTo().attribute(artifactType, fileExtension).attribute(javaModule, true);
205204
});
206205
}
207206

208-
private static Set<String> componentsOfInterest(ExtraJavaModuleInfoPluginExtension extension) {
209-
return extension.getModuleSpecs().get().values().stream().filter(ExtraJavaModuleInfoPlugin::needsDependencies).map(ModuleSpec::getIdentifier).collect(Collectors.toSet());
210-
}
211-
212-
private Stream<ResolvedComponentResult> filteredResolutionResult(Configuration configuration, Set<String> componentsOfInterest) {
207+
private Stream<Map.Entry<String, Configuration>> existingComponentsOfInterest(Configuration resolvable, ExtraJavaModuleInfoPluginExtension extension) {
208+
Set<String> componentsOfInterest = componentsOfInterest(extension);
213209
if (componentsOfInterest.isEmpty()) {
214210
return Stream.empty();
215211
}
216-
return configuration.getIncoming().getResolutionResult().getAllComponents().stream().filter(c -> componentsOfInterest.contains(ga(c.getId())));
212+
213+
return resolvable.getIncoming().getResolutionResult().getAllComponents().stream()
214+
.filter(c -> componentsOfInterest.contains(ga(c.getId())))
215+
.collect(Collectors.toMap(c -> c.getId().toString(), c -> resolvable)).entrySet().stream();
217216
}
218217

219-
private Map<String, Set<String>> toStringMap(Stream<ResolvedComponentResult> result) {
220-
return result.collect(Collectors.toMap(
221-
c -> ga(c.getId()),
222-
c -> c.getDependencies().stream().filter(ExtraJavaModuleInfoPlugin::filterComponentDependencies).map(ExtraJavaModuleInfoPlugin::ga).collect(Collectors.toSet()),
223-
(dependencies1, dependencies2) -> dependencies1));
218+
private static Set<String> componentsOfInterest(ExtraJavaModuleInfoPluginExtension extension) {
219+
return extension.getModuleSpecs().get().values().stream()
220+
.filter(ExtraJavaModuleInfoPlugin::needsDependencies)
221+
.map(ModuleSpec::getIdentifier)
222+
.collect(Collectors.toSet());
224223
}
225224

226225
private static boolean needsDependencies(ModuleSpec moduleSpec) {
227226
return moduleSpec instanceof ModuleInfo && ((ModuleInfo) moduleSpec).requireAllDefinedDependencies;
228227
}
229228

230-
private static boolean filterComponentDependencies(DependencyResult d) {
231-
if (d instanceof ResolvedDependencyResult) {
232-
Category category = ((ResolvedDependencyResult) d).getResolvedVariant().getAttributes().getAttribute(CATEGORY_ATTRIBUTE);
233-
String categoryUntyped = ((ResolvedDependencyResult) d).getResolvedVariant().getAttributes().getAttribute(CATEGORY_ATTRIBUTE_UNTYPED);
234-
return LIBRARY.equals(categoryUntyped) || (category != null && LIBRARY.equals(category.getName()));
235-
}
236-
return false;
237-
}
238-
239-
private static String ga(DependencyResult d) {
240-
if (d instanceof ResolvedDependencyResult) {
241-
return ga(((ResolvedDependencyResult) d).getSelected().getId());
242-
}
243-
return d.getRequested().getDisplayName();
244-
}
245-
246-
private static String ga(ComponentIdentifier id) {
229+
static String ga(ComponentIdentifier id) {
247230
if (id instanceof ModuleComponentIdentifier) {
248231
return ((ModuleComponentIdentifier) id).getGroup() + ":" + ((ModuleComponentIdentifier) id).getModule();
249232
}

src/main/java/org/gradlex/javamodule/moduleinfo/ExtraJavaModuleInfoTransform.java

Lines changed: 12 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -109,13 +109,7 @@ public interface Parameter extends TransformParameters {
109109
ListProperty<RegularFile> getMergeJars();
110110

111111
@Input
112-
MapProperty<String, Set<String>> getCompileClasspathDependencies();
113-
114-
@Input
115-
MapProperty<String, Set<String>> getRuntimeClasspathDependencies();
116-
117-
@Input
118-
MapProperty<String, Set<String>> getAnnotationProcessorClasspathDependencies();
112+
MapProperty<String, PublishedMetadata> getRequiresFromMetadata();
119113
}
120114

121115
@InputArtifact
@@ -370,41 +364,26 @@ private byte[] addModuleInfo(ModuleInfo moduleInfo, Map<String, List<String>> pr
370364
moduleVisitor.visitRequire("java.base", 0, null);
371365

372366
if (moduleInfo.requireAllDefinedDependencies) {
373-
Set<String> compileDependencies = getParameters().getCompileClasspathDependencies().get().get(moduleInfo.getIdentifier());
374-
Set<String> runtimeDependencies = getParameters().getRuntimeClasspathDependencies().get().get(moduleInfo.getIdentifier());
375-
Set<String> annotationProcessorDependencies = getParameters().getAnnotationProcessorClasspathDependencies().get().get(moduleInfo.getIdentifier());
367+
String fullIdentifier = moduleInfo.getIdentifier() + ":" + version;
368+
PublishedMetadata requires = getParameters().getRequiresFromMetadata().get().get(fullIdentifier);
376369

377-
if (compileDependencies == null && runtimeDependencies == null && annotationProcessorDependencies == null) {
370+
if (requires == null) {
378371
throw new RuntimeException("[requires directives from metadata] " +
379372
"Cannot find dependencies for '" + moduleInfo.getModuleName() + "'. " +
380373
"Are '" + moduleInfo.getIdentifier() + "' the correct component coordinates?");
381374
}
382375

383-
if (compileDependencies == null) {
384-
compileDependencies = Collections.emptySet();
385-
}
386-
if (runtimeDependencies == null) {
387-
runtimeDependencies = Collections.emptySet();
376+
for (String ga : requires.getRequires()) {
377+
String depModuleName = gaToModuleName(ga);
378+
moduleVisitor.visitRequire(depModuleName, 0, null);
388379
}
389-
if (annotationProcessorDependencies == null) {
390-
annotationProcessorDependencies = Collections.emptySet();
380+
for (String ga : requires.getRequiresTransitive()) {
381+
String depModuleName = gaToModuleName(ga);
382+
moduleVisitor.visitRequire(depModuleName, Opcodes.ACC_TRANSITIVE, null);
391383
}
392-
Set<String> allDependencies = new TreeSet<>();
393-
allDependencies.addAll(compileDependencies);
394-
allDependencies.addAll(runtimeDependencies);
395-
allDependencies.addAll(annotationProcessorDependencies);
396-
for (String ga : allDependencies) {
384+
for (String ga : requires.getRequiresStaticTransitive()) {
397385
String depModuleName = gaToModuleName(ga);
398-
if (compileDependencies.contains(ga) && runtimeDependencies.contains(ga)) {
399-
moduleVisitor.visitRequire(depModuleName, Opcodes.ACC_TRANSITIVE, null);
400-
} else if (runtimeDependencies.contains(ga) || annotationProcessorDependencies.contains(ga)) {
401-
// We can currently not identify for sure if a 'requires' is NOT transitive.
402-
// For that, we would need the 'compile classpath' of the module we are looking at right now.
403-
// The 'compileDependencies' set is based only on the 'compile classpath' of the final consumer.
404-
moduleVisitor.visitRequire(depModuleName, 0, null);
405-
} else if (compileDependencies.contains(ga)) {
406-
moduleVisitor.visitRequire(depModuleName, Opcodes.ACC_STATIC_PHASE, null);
407-
}
386+
moduleVisitor.visitRequire(depModuleName, Opcodes.ACC_STATIC_PHASE | Opcodes.ACC_TRANSITIVE, null);
408387
}
409388
}
410389

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/*
2+
* Copyright the GradleX team.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.gradlex.javamodule.moduleinfo;
18+
19+
import org.gradle.api.Project;
20+
import org.gradle.api.artifacts.Configuration;
21+
import org.gradle.api.artifacts.result.DependencyResult;
22+
import org.gradle.api.artifacts.result.ResolvedComponentResult;
23+
import org.gradle.api.artifacts.result.ResolvedDependencyResult;
24+
import org.gradle.api.attributes.Attribute;
25+
import org.gradle.api.attributes.Category;
26+
import org.gradle.api.attributes.Usage;
27+
28+
import java.io.Serializable;
29+
import java.util.ArrayList;
30+
import java.util.List;
31+
import java.util.stream.Collectors;
32+
import java.util.stream.Stream;
33+
34+
import static java.util.Objects.requireNonNull;
35+
import static org.gradle.api.attributes.Category.CATEGORY_ATTRIBUTE;
36+
import static org.gradle.api.attributes.Category.LIBRARY;
37+
import static org.gradle.api.attributes.Usage.USAGE_ATTRIBUTE;
38+
39+
public class PublishedMetadata implements Serializable {
40+
private static final Attribute<String> CATEGORY_ATTRIBUTE_UNTYPED = Attribute.of(CATEGORY_ATTRIBUTE.getName(), String.class);
41+
42+
private final String gav;
43+
private final List<String> requires = new ArrayList<>();
44+
private final List<String> requiresTransitive = new ArrayList<>();
45+
private final List<String> requiresStaticTransitive = new ArrayList<>();
46+
47+
PublishedMetadata(String gav, Configuration origin, Project project) {
48+
this.gav = gav;
49+
List<String> compileDependencies = componentVariant(origin, project, Usage.JAVA_API);
50+
List<String> runtimeDependencies = componentVariant(origin, project, Usage.JAVA_RUNTIME);
51+
52+
Stream.concat(compileDependencies.stream(), runtimeDependencies.stream()).distinct().forEach(ga -> {
53+
if (compileDependencies.contains(ga) && runtimeDependencies.contains(ga)) {
54+
requiresTransitive.add(ga);
55+
} else if (runtimeDependencies.contains(ga)) {
56+
requires.add(ga);
57+
} else if (compileDependencies.contains(ga)) {
58+
requiresStaticTransitive.add(ga);
59+
}
60+
});
61+
}
62+
63+
private List<String> componentVariant(Configuration origin, Project project, String usage) {
64+
Configuration singleComponentVariantResolver = project.getConfigurations().detachedConfiguration(project.getDependencies().create(gav));
65+
singleComponentVariantResolver.setCanBeConsumed(false);
66+
singleComponentVariantResolver.shouldResolveConsistentlyWith(origin);
67+
origin.getAttributes().keySet().forEach(a -> {
68+
@SuppressWarnings("rawtypes") Attribute untypedAttributeKey = a;
69+
//noinspection unchecked
70+
singleComponentVariantResolver.getAttributes().attribute(untypedAttributeKey, requireNonNull(origin.getAttributes().getAttribute(a)));
71+
});
72+
singleComponentVariantResolver.getAttributes().attribute(USAGE_ATTRIBUTE, project.getObjects().named(Usage.class, usage));
73+
return firstAndOnlyComponent(singleComponentVariantResolver).getDependencies().stream()
74+
.filter(PublishedMetadata::filterComponentDependencies)
75+
.map(PublishedMetadata::ga)
76+
.collect(Collectors.toList());
77+
}
78+
79+
private ResolvedComponentResult firstAndOnlyComponent(Configuration singleComponentVariantResolver) {
80+
ResolvedDependencyResult onlyResult = (ResolvedDependencyResult) singleComponentVariantResolver.getIncoming().getResolutionResult()
81+
.getRoot().getDependencies().iterator().next();
82+
return onlyResult.getSelected();
83+
}
84+
85+
private static boolean filterComponentDependencies(DependencyResult d) {
86+
if (d instanceof ResolvedDependencyResult) {
87+
Category category = ((ResolvedDependencyResult) d).getResolvedVariant().getAttributes().getAttribute(CATEGORY_ATTRIBUTE);
88+
String categoryUntyped = ((ResolvedDependencyResult) d).getResolvedVariant().getAttributes().getAttribute(CATEGORY_ATTRIBUTE_UNTYPED);
89+
return LIBRARY.equals(categoryUntyped) || (category != null && LIBRARY.equals(category.getName()));
90+
}
91+
return false;
92+
}
93+
94+
private static String ga(DependencyResult d) {
95+
if (d instanceof ResolvedDependencyResult) {
96+
return ExtraJavaModuleInfoPlugin.ga(((ResolvedDependencyResult) d).getSelected().getId());
97+
}
98+
return d.getRequested().getDisplayName();
99+
}
100+
101+
public String getGav() {
102+
return gav;
103+
}
104+
105+
public List<String> getRequires() {
106+
return requires;
107+
}
108+
109+
public List<String> getRequiresTransitive() {
110+
return requiresTransitive;
111+
}
112+
113+
public List<String> getRequiresStaticTransitive() {
114+
return requiresStaticTransitive;
115+
}
116+
}

0 commit comments

Comments
 (0)