Alexey Loubyansky
07/22/2025, 4:24 PMruntime or runtimeElements as a base variant but that introduces an ambiguity, which i'm struggling to find a way to avoid. Is there an example how it's supposed to be done?
Here is my playground plugin https://github.com/aloubyansky/playground/blob/gradle-comp-variants/plugin/src/main/java/org/example/PlaygroundPlugin.java
And here is the outcome of running it https://github.com/aloubyansky/playground/tree/gradle-comp-variants.
Thanks!tony
07/22/2025, 4:54 PMAlexey Loubyansky
07/22/2025, 8:20 PMruntimeElements as the base one and add a new attribute to it. But when I resolve a configuration, I don't ask for that attribute.
What I get in a disambiguation rule is a value for the attribute defined in my custom variant with consumer value null, since i didn't ask for it. And I can't seem to remove this variant as a choice. If that makes sense.Alexey Loubyansky
07/22/2025, 9:34 PMoff, for example.
The other variant would add a dependency that i need to the base variant and the new attribute with value on, for example.
Then in this case, i could add a disambiguation rule that would select the variant with value off if the consumer value for the new attribute is nullAlexey Loubyansky
07/22/2025, 9:35 PMtony
07/23/2025, 1:44 AMVampire
07/23/2025, 9:06 AMgreetingClasspath (which you did not configure in a non-legacy way with the "canbe" properties) misses attributes. As you do not request any attribute at all, Gradle does not really know what you are after.
If you for example add
config.attributes(attrs -> {
attrs.attribute(Category.CATEGORY_ATTRIBUTE, getObjectFactory().named(Category.class, Category.LIBRARY));
attrs.attribute(Usage.USAGE_ATTRIBUTE, getObjectFactory().named(Usage.class, Usage.JAVA_RUNTIME));
attrs.attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, getObjectFactory().named(LibraryElements.class, LibraryElements.JAR));
attrs.attribute(Bundling.BUNDLING_ATTRIBUTE, getObjectFactory().named(Bundling.class, Bundling.EXTERNAL));
attrs.attribute(TargetJvmEnvironment.TARGET_JVM_ENVIRONMENT_ATTRIBUTE, getObjectFactory().named(TargetJvmEnvironment.class, TargetJvmEnvironment.STANDARD_JVM));
attrs.attribute(Attribute.of("other-attr", String.class), "on");
});
your new variant will be matched.
Also, if you invent a new attribute, should usually always add it to the attribute schema too, otherwise some things will not work properly.Alexey Loubyansky
07/23/2025, 9:08 AMother-attrAlexey Loubyansky
07/23/2025, 9:08 AMLibraryElements.LIBRARY_ELEMENTS_ATTRIBUTEAlexey Loubyansky
07/23/2025, 9:09 AMAlexey Loubyansky
07/23/2025, 9:10 AMAlexey Loubyansky
07/23/2025, 9:10 AMAlexey Loubyansky
07/23/2025, 9:11 AMVampire
07/23/2025, 9:16 AMby adding a new variant with a new attribute to component (external) the way i'm doing it, i'm introducing ambiguity, i realize thatNot really, if you do not request the attribute, the original variant wins
Vampire
07/23/2025, 9:20 AMVampire
07/23/2025, 9:22 AMVampire
07/23/2025, 9:24 AMAlexey Loubyansky
07/23/2025, 9:24 AMattrs.attribute(Attribute.of("other-attr", String.class), "on"); from your suggestion, it will fail, right?Vampire
07/23/2025, 9:25 AMVampire
07/23/2025, 9:25 AMAlexey Loubyansky
07/23/2025, 9:25 AMVampire
07/23/2025, 9:25 AMVampire
07/23/2025, 9:26 AMAlexey Loubyansky
07/23/2025, 9:26 AMVampire
07/23/2025, 9:26 AMAlexey Loubyansky
07/23/2025, 9:30 AMdiff --git a/plugin/src/main/java/org/example/PlaygroundPlugin.java b/plugin/src/main/java/org/example/PlaygroundPlugin.java
index da768d7c..7ac16a1c 100644
--- a/plugin/src/main/java/org/example/PlaygroundPlugin.java
+++ b/plugin/src/main/java/org/example/PlaygroundPlugin.java
@@ -7,6 +7,11 @@ import org.gradle.api.Project;
import org.gradle.api.Plugin;
import org.gradle.api.artifacts.ComponentMetadataDetails;
import org.gradle.api.attributes.Attribute;
+import org.gradle.api.attributes.Bundling;
+import org.gradle.api.attributes.Category;
+import org.gradle.api.attributes.LibraryElements;
+import org.gradle.api.attributes.Usage;
+import org.gradle.api.attributes.java.TargetJvmEnvironment;
import org.gradle.api.plugins.JavaPlugin;
@@ -26,6 +31,13 @@ public class PlaygroundPlugin implements Plugin<Project> {
project.getConfigurations().register("greetingClasspath", config -> {
config.extendsFrom(project.getConfigurations().getByName(JavaPlugin.IMPLEMENTATION_CONFIGURATION_NAME));
+ config.attributes(attrs -> {
+ attrs.attribute(Category.CATEGORY_ATTRIBUTE, project.getObjects().named(Category.class, Category.LIBRARY));
+ attrs.attribute(Usage.USAGE_ATTRIBUTE, project.getObjects().named(Usage.class, Usage.JAVA_RUNTIME));
+ attrs.attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, project.getObjects().named(LibraryElements.class, LibraryElements.JAR));
+ attrs.attribute(Bundling.BUNDLING_ATTRIBUTE, project.getObjects().named(Bundling.class, Bundling.EXTERNAL));
+ attrs.attribute(TargetJvmEnvironment.TARGET_JVM_ENVIRONMENT_ATTRIBUTE, project.getObjects().named(TargetJvmEnvironment.class, TargetJvmEnvironment.STANDARD_JVM));
+ });
});
i get
$ ./gradlew :app:greeting
> Task :app:greeting FAILED
[Incubating] Problems report is available at: file:///home/aloubyansky/git/playground/build/reports/problems/problems-report.html
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:greeting'.
> Could not resolve all files for configuration ':app:greetingClasspath'.
> Could not resolve xom:xom:1.3.9.
Required by:
project :app
> Cannot choose between the available variants of xom:xom:1.3.9:
- otherVariant
- runtime
All of them match the consumer attributes:
- Variant 'otherVariant' capability 'xom:xom:1.3.9':
- Unmatched attributes:
- Provides org.gradle.category 'library' but the consumer didn't ask for it
- Provides org.gradle.libraryelements 'jar' but the consumer didn't ask for it
- Provides org.gradle.status 'release' but the consumer didn't ask for it
- Provides org.gradle.usage 'java-runtime' but the consumer didn't ask for it
- Provides other-attr 'on' but the consumer didn't ask for it
- Variant 'runtime' capability 'xom:xom:1.3.9':
- Unmatched attributes:
- Provides org.gradle.category 'library' but the consumer didn't ask for it
- Provides org.gradle.libraryelements 'jar' but the consumer didn't ask for it
- Provides org.gradle.status 'release' but the consumer didn't ask for it
- Provides org.gradle.usage 'java-runtime' but the consumer didn't ask for it
* Try:
> Ambiguity errors are explained in more detail at <https://docs.gradle.org/8.13/userguide/variant_model.html#sub:variant-ambiguity>.
> Review the variant matching algorithm at <https://docs.gradle.org/8.13/userguide/variant_attributes.html#sec:abm_algorithm>.
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
> Get more help at <https://help.gradle.org>.
BUILD FAILED in 473ms
5 actionable tasks: 2 executed, 1 from cache, 2 up-to-dateAlexey Loubyansky
07/23/2025, 9:31 AMattrs.attribute(Attribute.of("other-attr", String.class), "on"); but with that it also works w/o the rest of the attributes addedVampire
07/23/2025, 9:36 AMAlexey Loubyansky
07/23/2025, 9:37 AMVampire
07/23/2025, 9:37 AMVampire
07/23/2025, 9:37 AMAlexey Loubyansky
07/23/2025, 9:37 AMother-attrAlexey Loubyansky
07/23/2025, 9:37 AMVampire
07/23/2025, 9:38 AMVampire
07/23/2025, 9:38 AMVampire
07/23/2025, 9:39 AMAlexey Loubyansky
07/23/2025, 9:39 AMAlexey Loubyansky
07/23/2025, 9:40 AMcleanVampire
07/23/2025, 9:40 AMVampire
07/23/2025, 9:40 AM./gradlew app:dependencyInsight --configuration greetingClasspath --dependency xom:xomVampire
07/23/2025, 9:40 AM> Task :app:dependencyInsight
xom:xom:1.3.9
Variant runtime:
| Attribute Name | Provided | Requested |
|--------------------------------|--------------|--------------|
| org.gradle.status | release | |
| org.gradle.category | library | library |
| org.gradle.libraryelements | jar | jar |
| org.gradle.usage | java-runtime | java-runtime |
| org.gradle.dependency.bundling | | external |
| org.gradle.jvm.environment | | standard-jvm |
xom:xom:1.3.9
\--- greetingClasspath
A web-based, searchable dependency report is available by adding the --scan option.Alexey Loubyansky
07/23/2025, 9:41 AMVampire
07/23/2025, 9:42 AMVampire
07/23/2025, 9:42 AMAlexey Loubyansky
07/23/2025, 9:43 AMruntimeClasspath, always requests these attributes?Alexey Loubyansky
07/23/2025, 9:44 AMimplementation, i would somehow inherit the attributes relevant for that one and i would need to add mine "on top" of thatAlexey Loubyansky
07/23/2025, 9:45 AMVampire
07/23/2025, 9:48 AMjava-api variants.
But if the configuration is used as a runtime classpath, then it needs the java-runtime variants.
And so on.Vampire
07/23/2025, 9:49 AMimplementation there are no attributes defined, that would be useless, as it is only a dependency bucket where you declare dependencies.Vampire
07/23/2025, 9:49 AMcompileClasspath or runtimeClasspath but that wouldn't help either.
You would still only inherit the dependencies (additionally the compileOnly, resp. runtimeOnly), but not the attributes.Vampire
07/23/2025, 9:50 AMVampire
07/23/2025, 9:52 AMsourcesElements) for the resolved dependencies or can trigger artifact transforms that transform the resolved artifacts.
.......Vampire
07/23/2025, 9:54 AMAlexey Loubyansky
07/23/2025, 9:55 AMAlexey Loubyansky
07/23/2025, 9:55 AMVampire
07/23/2025, 9:55 AMAlexey Loubyansky
07/23/2025, 9:56 AM