Skip to content
This repository has been archived by the owner on Feb 11, 2022. It is now read-only.

Error with Gradle 3.4-rc-2: o.g.internal.component.Usage was renamed to UsageContext #112

Closed
jjohannes opened this issue Feb 8, 2017 · 8 comments

Comments

@jjohannes
Copy link

Using bintry-release in a com.android.library project with Gradle 3.4-rc-2 fails with the following exception:

Caused by: java.lang.NoClassDefFoundError: org/gradle/api/internal/component/Usage
        at com.novoda.gradle.release.AndroidArtifacts.from(AndroidArtifacts.groovy:49)

The cause for this is that Usage was renamed to UsageContext.

To avoid such problems in the future, I created an issue to discuss public API for publishing in Gradle, as we seem to miss something in this area. Please add your thoughts on the topic here: gradle/gradle#1361

@ouchadam
Copy link
Contributor

thanks for the heads up!

@bmuschko
Copy link

What's the reason for creating an implementation for SoftwareComponentInternal? That interface is an internal Gradle core class and shouldn't be used. Couldn't you have created a similar implementation to JavaArtifacts for AndroidArtifacts that doesn't require the use of internal APIs?

@mr-archano
Copy link
Contributor

mr-archano commented Apr 12, 2017

TL;DR: the problem we’re facing with the plugin is not easy to solve. The solution pointed out above is just not applicable (more below). The only feasible approach we found so far is to:

  • use the renamed internal class in our plugin
  • put a giant warning on the README stating Gradle support is now only 3.4+

Long story:

The plugin we produced does 2 things:

  1. streamlines the setup for the upload to bintray
  2. adds supports for pubbliation of .aar that is not provided by the maven publishing plugin (shipped with Gradle)

Point 2) is where the pain starts: we need to create a pom file listing all the dependencies of the library, but given there is no support out of the box in the maven plugin then we had to implement this ourselves. The public API we can use for this is called MavenPublication.from(SoftwareComponent). As stated in the javadoc there’s only support for SoftwareComponent produced by either the JavaPlugin or the WarPlugin, so we ended up adding an Android-aware implementation ourselves.

Unfortunately we can’t use the SoftwareComponent interface because of the downcast inside the implementation of MavenPublication assuming all the implementation of SoftwareComponent received are of a particular SoftwareComponentInternal type (see original code).

So basically we HAVE to implement the internal API if we want to publish something via the maven plugin and there is no workaround for that because the Android plugin is not exposing any SoftwareComponent. It’s either SoftwareComponentInternal or DefaultMavenPublication or the whole MavenPublishingPlugin we had to extend. And all of them are internal APIs.

Am I missing something obvious @bmuschko?

PS: Sorry for the late reply, I looked into this few weeks ago but then forgot to follow-up.

@bmuschko
Copy link

bmuschko commented Apr 18, 2017

@mr-archano In a nutshell this is what I was thinking in terms of using a public API while fulfilling your requirements:

  1. For your AAR file you create a dedicated task.
  2. You register that task with the Maven publish plugin using the artifact method.
  3. In order to include the dependencies you need you simply modify the POM at generation time using withXml.

Keep in mind that the code I provided would have to be adapted a bit in your binary plugin.

apply plugin: 'java'
apply plugin: 'maven-publish'

group = 'com.company'
version = '1.0'

dependencies {
    compile 'commons-lang:commons-lang:2.5'
}

repositories {
    mavenCentral()
}

task aarJar(type: Jar) {
    destinationDir = file("${buildDir}/outputs/aar")
    extension = "aar"
    from sourceSets.main.output
}

publishing {
    publications {
        aar(MavenPublication) {
            artifact aarJar
            pom.withXml {
                def dependenciesNode = asNode().appendNode('dependencies')

                configurations.compile.allDependencies.each {
                    def dependencyNode = dependenciesNode.appendNode('dependency')
                    dependencyNode.appendNode('groupId', it.group)
                    dependencyNode.appendNode('artifactId', it.name)
                    dependencyNode.appendNode('version', it.version)
                }
            }
        }
    }
    repositories {
        maven {
            url "$buildDir/repo"
        }
    }
}

@mr-archano
Copy link
Contributor

Thanks @bmuschko, I will take a look at this and let you know how it goes.

@passsy
Copy link
Contributor

passsy commented Apr 18, 2017

I already got it working this way but it felt wrong. I'm basically manually adding nodes to the pom XML and have to duplicate a lot of code which is already there (but internal).

  • manually filter for compile and runtime dependencies and sort them accordingly
  • custom handling from project dependencies
  • remove duplicates

I think it's harder to maintain than to adjust the internal based implementation from time to time.

Offtopic: My new favourite class is ProjectDependencyArtifactIdExtractorHack

@bmuschko
Copy link

@passsy I created an issue to address the problem. The appropriate solution should expose a public API for declaring a publishable software component without the need of using an internal API.

I think it's harder to maintain than to adjust the internal based implementation from time to time.

Keep in mind that you'll be breaking backward compatibility for your plugin. Users will have to use 3.4 in order to consume it. That might or might not be acceptable for your user base.

@frapontillo
Copy link

This should have been fixed in 0.5.0.
Please re-open the issue if you're still experiencing the problem.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants