spring-projects / spring-boot

Spring Boot
https://spring.io/projects/spring-boot
Apache License 2.0
74.96k stars 40.65k forks source link

bootRepackage fails to package dependencies from the new gradle Java Library plugin #9143

Closed BPaasch closed 7 years ago

BPaasch commented 7 years ago

Bug report

When using the new Gradle Java Library plugin and declaring dependencies using the api or implementation configurations, the bootRepackage task doesn't package the dependencies into the final jar.

If I replace the declared dependencies using the compile configuration, then the bootRepackage task does package them into the jar. However, the gradle documentation says to ignore this configuration:

The compile, testCompile, runtime and testRuntime configurations inherited from the Java plugin are still available but are deprecated. You should avoid using them, as they are only kept for backwards compatibility.

Example:

/*
 * This build file was generated by the Gradle 'init' task.
 *
 * This generated file contains a sample Java Library project to get you started.
 * For more details take a look at the Java Libraries chapter in the Gradle
 * user guide available at https://docs.gradle.org/3.5/userguide/java_library_plugin.html
 */

// Apply the java-library plugin to add support for Java Library
apply plugin: 'java-library'
apply plugin: 'org.springframework.boot'

buildscript {
  repositories {
    mavenCentral()
  }

  dependencies {
    classpath "org.springframework.boot:spring-boot-gradle-plugin:1.5.3.RELEASE"
  }
}

// In this section you declare where to find the dependencies of your project
repositories {
    // Use jcenter for resolving your dependencies.
    // You can declare any Maven/Ivy/file repository here.
    jcenter()
}

springBoot {
    mainClass = 'Library'
}

dependencies {
    // This dependency is exported to consumers, that is to say found on their compile classpath.
    api 'org.apache.commons:commons-math3:3.6.1'

    // This dependency is used internally, and not exposed to consumers on their own compile classpath.
    implementation 'com.google.guava:guava:21.0'

    // Use JUnit test framework
    testImplementation 'junit:junit:4.12'
}
wilkinsona commented 7 years ago

The repackaging includes everything in the runtime configuration which is why dependencies in the api and implementation configurations are not being included. 2.0 snapshots are not affected by this problem as the new bootJar task doesn't deal with configurations directly. Instead, it uses the runtime class path of the main source set.

In 1.5 and earlier, you can configure a custom configuration that will have its dependencies packaged in the jar. Ideally, this would be possible:

bootRepackage {
    customConfiguration = 'implementation'
}

Unfortunately, it fails as Gradle does not allow the implementation configuration to be resolved directly. Instead, you need to introduce some indirection in the form of another configuration that extends implementation:

configurations {
    custom {
        it.extendsFrom implementation
    }
}

bootRepackage {
    customConfiguration = 'implementation'
}

With this in place, both commons-math3 and guava are included in the jar.

wilkinsona commented 7 years ago

I also meant to say above that it seems rather strange to me to be applying Gradle's Library plugin to a project that's building a Spring Boot Application. It's rather rare (and not recommended) for a Spring Boot application to be used as a dependency so I'm surprised that you'd want to build it as a library. Have I missed a usecase here?

BPaasch commented 7 years ago

Thank you for the explanation. I figured that there might be some configuration to get it to work.

Also, no there's no missed use-case. I realize now that I should have been using the Java plugin all along. For some reason, I thought that the Java plugin was being replaced by the Java Library plugin.

mikepii commented 6 years ago

@wilkinsona thank you for posting the workaround, it helped me use the new implementation dependency type in Gradle 4.7 (as compile is deprecated in both the Java plugin and the Java Library plugin). I had to change it to customConfiguration = 'custom' to match the new configuration's name

bric3 commented 5 years ago

@wilkinsona This is very interesting, I think this workaround should be documented somewhere here : https://docs.spring.io/spring-boot/docs/1.5.20.RELEASE/reference/html/build-tool-plugins-gradle-plugin.html. And indeed compile configuration is deprecated in the java-plugin as well : https://docs.gradle.org/5.3.1/userguide/java_plugin.html#tab:configurations.

I know that Spring Boot 1.5.x is reaching end of life soon, but it allows a decoupled migration path for those that updates their gradle configuration first.

KENNYSOFT commented 2 years ago

May add it.extendsFrom runtimeOnly also.