Build simple custom plugin like "com.android.application"

i am building a custom plugin like android gradle plugin (com.android.application)
i simply define two configurations (implementation, compileClasspath)

public class MypluginPlugin implements Plugin<Project> {
    public void apply(Project project) {
        System.out.println(">>>>>>> MyPlugin Configuration");

        ConfigurationContainer configureContainer = project.getConfigurations();
        Configuration config = configureContainer.create("implementation");
        config.setCanBeDeclared(true);
        config.setCanBeResolved(false);
        config.setCanBeConsumed(false);

        Configuration myConfig2 = configureContainer.create("compileClasspath");
        myConfig2.extendsFrom(config);
        myConfig2.setCanBeDeclared(true);
        myConfig2.setCanBeResolved(true);
        myConfig2.setCanBeConsumed(false);

and i use the plugin in a gradle project (8.14.3)

buildscript {
    dependencies {
        classpath files("C:/Users/Admin/Desktop/code/android-test/simple-app/myplugin/plugin/build/libs/plugin.jar")
    }
}
apply plugin: 'org.example.greeting'

dependencies {
    implementation("androidx.lifecycle:lifecycle-viewmodel:2.9.2")
}

when i run ./gradlew :app:dependencies --configuration compileClasspath

myConfig2
\--- androidx.lifecycle:lifecycle-viewmodel:2.9.2
     \--- androidx.lifecycle:lifecycle-viewmodel-desktop:2.9.2
          +--- androidx.annotation:annotation:1.9.1
          |    \--- androidx.annotation:annotation-jvm:1.9.1
          |         \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.0.21
          |              \--- org.jetbrains:annotations:13.0 -> 23.0.0
          +--- org.jetbrains.kotlin:kotlin-stdlib -> 2.0.21 (*)
          +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1
          |    \--- org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.8.1
          |         +--- org.jetbrains:annotations:23.0.0
          |         +--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.8.1
          |         |    +--- org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.8.1 (c)
          |         |    \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 (c)
          |         \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.21 -> 2.0.21 (*)
          \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.21 (c)

it resolves androidx.lifecycle:lifecycle-viewmodel-desktop.
but i expected androidx.lifecycle:lifecycle-viewmodel-android like “com.android.application” plugin works.

i try to debug a configuration of “com.android.application” named is releaseCompileClasspath
i see i have five attributes

      com.android.build.api.attributes.BuildTypeAttr: release
      org.gradle.usage: java-api
      org.gradle.jvm.environment: android
      com.android.build.api.attributes.AgpVersionAttr: 8.11.0
      org.gradle.category: library
      org.jetbrains.kotlin.platform.type: androidJvm

so i also try to add these attributes to my compileClasspath.

public class MypluginPlugin implements Plugin<Project> {
    public void apply(Project project) {
        System.out.println(">>>>>>> MyPlugin Configuration");

        ConfigurationContainer configureContainer = project.getConfigurations();
        Configuration config = configureContainer.create("implementation");
        config.setCanBeDeclared(true);
        config.setCanBeResolved(false);
        config.setCanBeConsumed(false);

        Configuration myConfig2 = configureContainer.create("compileClasspath");
        myConfig2.extendsFrom(config);
        myConfig2.setCanBeDeclared(true);
        myConfig2.setCanBeResolved(true);
        myConfig2.setCanBeConsumed(false);

        var myConfig2Atts = myConfig2.getAttributes();
        myConfig2Atts.attribute(Attribute.of("com.android.build.api.attributes.BuildTypeAttr", String.class), "release");
        myConfig2Atts.attribute(Attribute.of("org.gradle.usage", String.class), "java-api");
        myConfig2Atts.attribute(Attribute.of("org.gradle.jvm.environment", String.class), "android");
        myConfig2Atts.attribute(Attribute.of("com.android.build.api.attributes.AgpVersionAttr", String.class), "8.11.0");
        myConfig2Atts.attribute(Attribute.of("org.gradle.category", String.class), "library");
        myConfig2Atts.attribute(Attribute.of("org.jetbrains.kotlin.platform.type", String.class), "androidJvm");

when i run ./gradlew :app:dependencies --configuration compileClasspath

\--- androidx.lifecycle:lifecycle-viewmodel:2.9.2
     \--- androidx.lifecycle:lifecycle-viewmodel-android:2.9.2
          +--- androidx.annotation:annotation:1.9.1 FAILED
          +--- org.jetbrains.kotlin:kotlin-stdlib FAILED
          +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1 FAILED
          +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1
          |    \--- org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.8.1
          |         +--- org.jetbrains:annotations:23.0.0
          |         +--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.8.1
          |         |    +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1 FAILED
          |         |    +--- org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.8.1 (c)
          |         |    \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 (c)
          |         \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.21 FAILED
          \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.21 ->  FAILED

it have resolved androidx.lifecycle:lifecycle-viewmodel-android.
but androidx.annotation:annotation:1.9.1 FAILED
i try creating a task to resolve.

project.getTasks().register("greeting", task -> {
            task.doLast(s -> {
                var compileClasspath = configureContainer.getByName("compileClasspath");
                compileClasspath.resolve().forEach(f -> {
                    System.out.println(f.getName());
                });
            });
        });

when i run ./gradlew :app:greeting

> Could not resolve androidx.annotation:annotation:1.9.1.
     Required by:
         project :app > androidx.lifecycle:lifecycle-viewmodel:2.9.2 > androidx.lifecycle:lifecycle-viewmodel-android:2.9.2 
      > No matching variant of androidx.annotation:annotation:1.9.1 was found. The consumer was configured to find attribute 'com.android.build.api.attributes.AgpVersionAttr' with value '8.11.0', attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'release', attribute 'org.gradle.category' with value 'library', attribute 'org.gradle.jvm.environment' with value 'android', attribute 'org.gradle.usage' with value 'java-api', attribute 'org.jetbrains.kotlin.platform.type' with 
value 'androidJvm' but:
          - Variant 'androidNativeArm32ApiElements-published' declares attribute 'org.gradle.category' with value 'library':              - Incompatible because this component declares attribute 'org.gradle.jvm.environment' with value 'non-jvm', attribute 'org.gradle.usage' with value 'kotlin-api', attribute 'org.jetbrains.kotlin.platform.type' with value 'native' and the consumer needed attribute 'org.gradle.jvm.environment' with value 'android', attribute 'org.gradle.usage' with value 'java-api', attribute 'org.jetbrains.kotlin.platform.type' with value 'androidJvm'
              - Other compatible attributes:
                  - Doesn't say anything about com.android.build.api.attributes.AgpVersionAttr (required '8.11.0')
                  - Doesn't say anything about com.android.build.api.attributes.BuildTypeAttr (required 'release')
          - Variant 'androidNativeArm32SourcesElements-published':

i think the attributes in compileClasspath configuration is matching with an variant name “releaseApiElements-published” in “androidx.lifecycle:lifecycle-viewmodel-android:2.9.2”
but not matching with any variants of dependencies of it like “androidx.annotation:annotation:1.9.1”
i see variants in “androidx.annotation:annotation:1.9.1” needing different attributes.

- Variant 'jvmApiElements-published' declares attribute 'org.gradle.category' with value 'library', attribute 'org.gradle.usage' with value 'java-api', attribute 'org.jetbrains.kotlin.platform.type' with value 'jvm':
              - Incompatible because this component declares attribute 'org.gradle.jvm.environment' with value 'standard-jvm' and the consumer needed attribute 'org.gradle.jvm.environment' with value 'android'
              - Other compatible attributes:
                  - Doesn't say anything about com.android.build.api.attributes.AgpVersionAttr (required '8.11.0')
                  - Doesn't say anything about com.android.build.api.attributes.BuildTypeAttr (required 'release')

i wonder releaseCompileClasspath configuration in “com.android.application” have any implemetation like (resolutionStrategy or something)
i also wonder somehow to specify attributes for transitive dependency like “androidx.annotation:annotation:1.9.1”

As a general thing, if you anyway use incubating API like setCanBeDeclared, then better use the convenience helpers like configurationContainer.resolvable(...) and configurationContainer.dependencyScope(...), then you also cannot make the wrong setup you did to declare the config2 as declarable and resolvable.

Besides that, there is more to attributes than you envision it seems.
For one, you should not declare new attributes that are called like the existing ones, but use the attributes that are defined like myConfig2Atts.attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_API)).

Also, an attribute is not only a name/value pair.
For itself yes, but the one the declares an attribute should also register it in the attribute scheme so that compatibility rules and disambiguation rules and artifact transforms can be handled properly.
And the one declaring an attribute often (an in your case they do) declare compatibility rules (like "if a consumer asks for “android”, then “jvm” is also fine if there is no “android” variant which you would need here) and disambiguation rules if multiple variants match the request and the disambiguation rule can solve the conflict.

All this you miss by simply redeclaring attributes without the semantic rules they should also have.
For the built-in attributes for example you would apply the jvm-ecosystem plugin, so that the attributes and rules for the built-in JVM attributes are registered.

Alternatively you can of course dig into source codes and try to replicate all the code that sets up the rules that AGP and KPG configure for example.

What can also help you with your wheel-reinventing is the dependencyInsight task. It also shows you exactly what was requested and why which variant is discarded or not.

Thanks for your reply.
I added compatibility rule to two attributes “org.gradle.jvm.environment” and “org.jetbrains.kotlin.platform.type” and it works.

class JvmEnvironmentCompatibilityRule implements AttributeCompatibilityRule<String> {
    @Override
    public void execute(CompatibilityCheckDetails<String> details) {
        System.out.println("JvmEnvironmentCompatibilityRule: " + details.getConsumerValue() + " " + details.getProducerValue());
        if(
            details.getConsumerValue().equals("android")
            && 
            details.getProducerValue().equals("standard-jvm")
        ){
            details.compatible();
        }
    }
}
class KotlinPlatformTypeCompatibilityRule implements AttributeCompatibilityRule<String> {
    @Override
    public void execute(CompatibilityCheckDetails<String> details) {
        System.out.println("KotlinPlatformTypeCompatibilityRule: " + details.getConsumerValue() + " " + details.getProducerValue());
        if(
            details.getConsumerValue().equals("androidJvm")
            && 
            details.getProducerValue().equals("jvm")
        ){
            details.compatible();
        }
    }
}
        project.getDependencies().getAttributesSchema().attribute(
            Attribute.of("org.gradle.jvm.environment", String.class)
        )
        .getCompatibilityRules()
        .add(JvmEnvironmentCompatibilityRule.class);
        project.getDependencies().getAttributesSchema().attribute(
            Attribute.of("org.jetbrains.kotlin.platform.type", String.class)
        )
        .getCompatibilityRules()
        .add(KotlinPlatformTypeCompatibilityRule.class);