Referencing a subprojects Java SoftwareComponent

I have a repository that due to legacy reasons generates multiple JAR files. Each of these JARs represent different “flavors” of the same artifact (exclusively) and I’m modeling them as maven classifiers when publishing them.

My repo structure looks something like this:

build.gradle -- (Responsible for final artifact construction and publishing)
bindings/
  main/
    build.gradle -- (Responsible for building new bindings)
  legacy/
    build.gradle -- (Responsible for building `legacy` classifier jar for old bindings)
  mini/
    build.gradle -- (Responsible for building 'mini' classifier jar for zero dependency bindings)

While not totally satisfied with it, I’ve managed to get this to work by not including the top level software component and instead referencing each jar as an artifact (and the task that builds it in the subproject) in it’s own isolated configuration that I can ensure only selects a single JAR artifact via the attributes on resolution.

configurations {
  jar {
    canBeResolved = true
    canBeConsumed = false
    attributes {
      //Attributes to select the JAR file only
    }
  }
  legacyJar {
    //Same as jar essentially
  }
}

dependencies {
  jar projects.bindings.main
  legacyJar projects.bindings.legacy
}

publishing {
  publications {
    mavenJava(MavenPublication) {
      artifact(configurations.jar.singleFile) {
        builtBy projects.bindings.main.dependencyProject.jar
      }
      artifact(configurations.legacyJar.singleFile) {
        builtBy projects.bindings.legacy.dependencyProject.jar
        classifier = 'legacy'
      }
     //Same for mini
    }
  }
}

The issue is that this means the SoftwareComponent exposed by the java plugin isn’t properly linked when constructing the MavenPublication. While these bindings subprojects all share the same dependency list (or have their dependencies included in the jar) there’s not a way to express that by say, using from(projects.bindings.main.dependencyProject.components.java) (or any flavor of that) as the java component can’t be resolved.

So at a high level, I’m looking to reference the SoftwareComponent of another project and treat publishing as a separate project. I’m guessing the answers will be “you probably shouldn’t do that” and that I should be publishing a separate module for each binding flavor (which is fine, and I understand why that would be) but curious as to how this could be solved.

Not really an answer to the actual question, but regarding your last sentence,
maybe you should indeed not do it, but consider using feature variants instead of separate modules.
Feature variants are the proper way to do what in Maven is often done using classifiers, non Gradle consumers still can use classifiers, Gradle consumers can properly pick the feature variant they want conveniently. :slight_smile:

1 Like

I’m going to try your suggestion and post my results here, if variants can be consumed via classifiers that would solve my problem exactly.

That ended up working exactly as I had hoped.

To anyone who stumbles across this later, the solution was to properly create configurations with attributes (essentially acting as classifiers) and then for maven interop to ensure when adding the artifacts to the configuration to explicitly mention the classifiers.

1 Like