3

I'm having a problem on a larger multi-project build that I was migrating from Gradle 4 to 5, and replicated the issue on a smaller, more concise build to demonstrate the issue.

I have 2 projects in the build. One is a dependency (basic library) used by the other.

demo (root project)
|- build.gradle
|
|--- demo-web
|---|- build.gradle
|
|--- demo-dependency
|---|- build.gradle

Snippet of demo-web: build.gradle

...
dependencies {
    implementation project(':demo-dependency')
    ...
}
...

The dependency project defines one class that is used in the web project, DownstreamThing.

The web project attempts to use that to construct its own object, but during a build on the root project level, it fails.

> ./gradlew build
> Task :demo-web:test

com.example.demo.ThingTest > testThing FAILED
    java.lang.NoClassDefFoundError at ThingTest.java:12
        Caused by: java.lang.ClassNotFoundException at ThingTest.java:12

ThingTest.java

    @Test
    public void testThing() {
        DownstreamThing t =  new DownstreamThing(); //line 12, ClassNotFoundException
        assertTrue(t != null);
    }

I didn't have any trouble with this in Gradle 4, but only in Gradle 5. Why is the dependency not being found during the test task?

Full source for the example is here: https://bitbucket.org/travelsized/gradle-problem/src/master/

M. Justin
  • 14,487
  • 7
  • 91
  • 130

2 Answers2

3

I believe he reason you are getting that exception is because you have applied the Spring Boot plugin to the demo-dependency project. What this plugin does is to repackage the jar file to a fat jar that needs a special classloader to load the content.

You can still use the Spring Boot dependencies (e.g. the starters) in the dependency project without the plugin. So if you can, just remove it.

If there is a particular reason why you have it, you will need to keep the original jar file so that is used as the actual dependency. For Spring Boot 1.5.x, you can do that with something like this:

bootRepackage {
    classifier = "boot"
}

bootJar {
    enabled = true
}

But do note that I don't think Spring Boot 1.5 is fully compatible with Gradle 5 and later (at this time we are on 6.0), so you might need to either downgrade Gradle or upgrade Spring Boot.

Bjørn Vester
  • 6,851
  • 1
  • 20
  • 20
  • Nice direction, in Kotlin it's worked for me when I removed `apply(plugin = "org.springframework.boot")` from root build.gradle and applied for each submodule EXCEPT **common** module – E.Big Nov 05 '20 at 16:57
3

Bjørn Vester's answer got me pointed in the right direction. The spring-boot plugin was causing the jar tasks to go awry. I needed to make sure that the bootJar task was disabled for the dependency while the jar task was enabled.

The changes in the configuration to do this between versions of Gradle and the Spring Boot plugin made this get lost in the upgrades.

Previously, I could specify a classifier for the jar post-boot:

bootRepackage  {
    classifier = 'exec'
}

Now, I need to enable and disable the appropriate tasks:

bootJar {
    enabled = false
}

jar {
    enabled = true
    archiveBaseName = "demo-dependency"
}

In the larger project, I previously had a jar task that specified the archiveBaseName, but didn't explicitly enable it to override the bootJar task. Once I made the above changes (while keeping the boot plugins in place), things started working.