Gradle using artifact with classifier instead of what I asked for. New .module file missing info

I’m using Gradle 6.2,
I have an artifact that has an obfuscated jar - without a classifier, and an unobfuscated jar with the classifier ‘unobfuscated’.

My build depends on the artifact without a classifier, yet the artifact that is downloaded and used is the one with the classifier.

I believe this is caused by newer Gradle versions publishing the new .module file that only mentions the unobfuscated jar.

The Gradle project that publishes the artifact in question uses the ‘maven-publish’ plugin. It has the jar task configured to use the ‘unobfuscated’ classifier, and it has a task that runs ProGuard to create a jar that is published without a classifier. It seems that Gradle is unable to get artifact that has no classifier (which is published to an Artifactory Maven repository).

How do I fix this my other project to use the jar without the classifier as it requests?

There seem to be two possibilities:
Disable the .module metadata generation

    tasks.withType(GenerateModuleMetadata) {
        enabled = false
    }

or find a way to add the obfuscated artifact with no classifier to the .module metadata.

Can that be done?

For now I have gone with the first option as it appears Gradle is broken when resolving dependencies with .module metadata in that only the artifact that was published from ‘components.java’ is resolved if it has a classifier and the artifact requested does not have a classifier.

Hi @swpalmer,

This should, and can, be solved on the publishing side. Gradle Module Metadata is there to have enough information about all variants you want to expose in the metadata.

Because the default setup takes the result of the jar task as the artifact for the standard Java library variant - apiElements and runtimeElements - you have the effect you are seeing. It works with pom, because the artifact name is not in the POM metadata and the one without classifier is taken by default when resolving.

You probably want to do one or two things:

  1. change the artifact of the standard variants to use obfuscated jar instead of the one produced by the jar task
  2. Add another variant for the unobfuscated jar (if you want to expose that)

The first would restore the situation you had before. You can do it like this:

// assuming 'obfuscatedJar' is the task producing the jar you want to publish
configurations {
    runtimeElements.outgoing.artifacts.clear()
    runtimeElements.outgoing.artifact(obfuscatedJar)
    apiElements.outgoing.artifacts.clear()
    apiElements.outgoing.artifact(obfuscatedJar)
}

You can also add more variants for the unobfuscated jar if you want to expose it in the metadata: https://docs.gradle.org/current/userguide/publishing_customization.html#sec:adding-variants-to-existing-components

1 Like

I would really love to see a sample with the “right way” to publish obfuscated and unobfuscated jars for a java-library. I.e. ‘unobfuscated’ for debug and internal developers and the standard output being obfuscated for external consumption. Similar to the example of conditional publishing of a source jar that is shown here https://docs.gradle.org/current/userguide/publishing_customization.html#sec:publishing_maven:conditional_publishing

I went to the link (“adding variants to existing components”), I looked at the documentation for the java-library plugin (my code is based on the older ‘java’ plugin though) and found the “runtimeElements” and “apiElements” configurations. But when I look at the docs for a configuration, here: https://docs.gradle.org/current/dsl/org.gradle.api.artifacts.Configuration.html, there is no ‘outgoing’ member documented. I’m finding it difficult to dig in to the docs and understand this. Docs here https://docs.gradle.org/current/dsl/org.gradle.api.artifacts.Configuration.html don’t even mention ‘outgoing’. I have to know to look into the API docs here https://docs.gradle.org/current/javadoc/org/gradle/api/artifacts/Configuration.html to see that it exists. Then I have to decode how a Maven ‘classifier’ might relate to a Gradle ‘variant’ … which I havent’ yet figured out. When I produce the default obfuscated jar, I want it in addition to the unobfuscated jar that has the ‘unobfuscated’ classifier - so is is unclear if runtimeElements.outgoing.artifacts.clear() and apiElements.outgoing.artifacts.clear() is the correct thing to do. I think so, because I think I need it to be added as a different ‘variant’

Then I have to wonder if I am handling the output jar of this project properly in terms of having it as a dependency for peer projects. I want to depend on the obfuscated or unobfuscated jar depending on a flag I pass to the build… So for internal debugging I can have peer projects depend on the unobfuscated jar. I never want an unobfuscated jar to be the default artifact that is published as it would be too easy to accidentally use it. That’s why I have the default jar task add the ‘unobfuscated’ classifier in the first place. You aren’t supposed to be able to get it as a dependency unless you are explicit about it.

Is it not a bug that Gradle will use an artifact with a classifier, when the artifact asked for was without a classifier? Should it not have simply failed to resolve the artifact?

There are a lot of parts to this. For example I currently have:

configurations {
	outputJar.extendsFrom(compile) // to get dependencies not just the one jar (obfuscated or unobfuscated)
}

artifacts {
	archives(file("$buildDir/proguard/${project.name}.jar")) { builtBy obfuscate }
	archives(file("$buildDir/proguard/proguard_map.txt")) {
		name "${project.name}"
		classifier 'proguard_map'
		builtBy obfuscate
	}
	archives(file("$buildDir/proguard/proguard_seeds.txt")) {
		name "${project.name}"
		classifier 'proguard_seeds'
		builtBy obfuscate
	}
	if (doObfuscation) {
		println "\n\n *** Using ProGuard-obfuscated jar as outputJar artifact ***"
		println " *** Use -Punobfuscated=true to use the uobfuscated artifact ***\n\n"
		outputJar(file("$buildDir/proguard/${project.name}.jar")) { builtBy obfuscate }
	} else {
		println "\n\n *** Using unobfuscated jar as outputJar artifact ***\n\n"
		outputJar jar
	}
}

and I have peer projects depend on the ‘outputJar’ configuration.
(I’m not sure if I needed to put the proguard map and seeds files in the ‘archives’ configuration. They are handled separately in the publishing block as additional artifacts attached to the publication.)

1 Like

My initial attempts to add an unobfuscated variant results in:

Windows Terminal

Invalid publication ‘myLib’:

  • Variant ‘unobfuscated’ must declare at least one attribute.