4
votes

TL;DR Two gradle plugins use different versions of the same dependency, resulting in compile errors when one of the plugins is invoked.

The Situation

  1. I have a Java project compiled using Gradle 4.x.

  2. The project relies on two plugins: gradle-jaxb-plugin and serenity-gradle-plugin.

  3. Both plugins share a dependency, guice.

The Problem

I need to upgrade one of the plugins (serenety). The upgrade results in a conflict at the point in which the jaxb plugin is invoked.

...
Caused by: java.lang.NoClassDefFoundError: com/google/inject/internal/util/$Maps
        at com.google.inject.assistedinject.BindingCollector.<init>(BindingCollector.java:34)
        at com.google.inject.assistedinject.FactoryModuleBuilder.<init>(FactoryModuleBuilder.java:206)
        at org.openrepose.gradle.plugins.jaxb.schema.guice.DocSlurperModule.configure(DocSlurperModule.groovy:43)
...

I did some sleuthing and googling, and am fairly sure that the issue is rooted in the fact that the version of the serenity plugin uses guice 4.x when it used to use guice 3.x. The jaxb plugin uses guice 3.x.

The Question

How do I separate the plugin dependencies from one another? I would like to include both plugins, but it appears that gradle will take the highest dependency set and use that everywhere.

The Code

Here are the relevant portions of my build.gradle

buildscript {
    repositories {
        mavenCentral()
        maven { url 'https://plugins.gradle.org/m2/' }
    }
    dependencies {
        classpath 'gradle.plugin.org.openrepose:gradle-jaxb-plugin:2.4.1'
        classpath 'net.serenity-bdd:serenity-gradle-plugin:1.5.1'
    }
}
...
project(':integration-tests') {
    apply plugin: 'java'
    apply plugin: 'net.serenity-bdd.aggregator'
    ...
}
...
project(':cms-business-model') {
    apply plugin: 'org.openrepose.gradle.plugins.jaxb'
    apply plugin: 'java'
    ...
}

Note: You can replicate the issue by adding the serenity 1.5.1 plugin to the classpath dependencies block of the jaxb plugin examples

1

1 Answers

4
votes

TL;DR: When Gradle plugins share a dependency but use different versions of that dependency only the highest version is actually used. You have to explicitly exclude the higher-dependency version.

The conflict here came because the jaxb plugin depends on guice:3.0 AND guice-assistedinject:3.0.

When serenity uses guice:4.0 there was a version mismatch between guice:4.0 and guice-assistedinject:3.0

The solution is to exclude the guice dependency from serenity, therefore falling back on guice:3.0

Updated Code

buildscript {
    repositories {
        mavenCentral()
        maven { url 'https://plugins.gradle.org/m2/' }
    }
    dependencies {
        classpath 'gradle.plugin.org.openrepose:gradle-jaxb-plugin:2.4.1'
        classpath ('net.serenity-bdd:serenity-gradle-plugin:1.5.1') {
            exclude group: 'com.google.inject', module:'guice'
        }
    }
}
...

Alternative Solution

Another possibility may have been to require guice-assistedinject:4.0, but the above worked so I didn't continue to explore.