Dependencies on configuration of a subproject

I have a multi project with 2 layers of subprojects as follow

root
|—subProj1
|—subProj2
|----subProj21
|----subProj22

Project subProj21 has 2 sourcetSets : ‘main’ and ‘api’

I would like subProj22 compile against the classes only on ‘api’ sourceSet.
As subProj21 applies the ‘java-library’ plugin, I thought to use the ‘apiImplementation’ configuration.

In build.gradle in subProj22, I’ve tried the following syntaxes

dependencies {
    api project(path: ':subProj2:subProj21', configuration: 'apiImplementation')
}

Could not resolve all task dependencies for configuration ‘:subProj2:subProj22:compileClasspath’.
Could not resolve project :subProj2:subProj21.
Required by:
project :subProj2:subProj22

dependencies {
    api project(':subProj2:subProj21').configurations['apiImplementation']
}

A problem occurred evaluating project ‘:subProj2:subProj22’.
Currently you can only declare dependencies on configurations from the same project.

If a declare the subProj2 as the root project having both subProj21 and 22, both syntaxes are accepted and compile works perfectly.

Thanks for help.

In general, this would work (instead of apiImplementation you would need to use apiCompileClasspath). But this is the discouraged “old” approach of doing this.

You should instead use variant-aware resolution which should perfectly fit your use case.
https://docs.gradle.org/current/userguide/variant_model.html
https://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_configurations_graph

There are then many options how you can identify and match variants. If I interpret what you want to do correctly, you always only need to depend on classes from api at compile time and all classes at runtime, correct? Then you can modify the existing apiElements and runtimeElement variants. Something like this:

configurations {
    apiElements {
        // for running the 'jar' (main) variant is used, so we only modify that
        // 'main' is already added by default
        outgoing.artifact(apiJar)
    }
    apiElements {
        // for compilation the 'classes' variant is used, so we only modify that
        outgoing.variants['classes'].artifacts.clear() // remove 'main'
        sourceSets.api.output.classesDirs.each {
            outgoing.variants['classes'].artifact(it)
        }
    }
}

In you dependencies, you then only depend on a project:

implementation project(':subProj2:subProj21')

Gradle will automatically only select the “api” classes when compiling.