From 3bfc6b1a4bfbfc49d86bd4f5625d008520692609 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 21 Apr 2016 11:37:40 +0100 Subject: [PATCH] Avoid packaging two versions of same dependency in Gradle repackaging Previously, the Gradle plugin would include all of the dependencies from both the compile and runtime configurations in the repackaged jar. In the unlikely event that the compile and runtime configurations contained different versions of the same dependency, this would lead to both versions of the dependency being packaged in the jar file. The runtime configuration extends the compile configuration so, in normal circumstances, it will contain a superset of the compile configuration's dependencies. In the situation described above where the two configurations contain different versions of the same dependency the runtime configuration will only contain whichever version of the two dependencies has "won". By default, this will be the dependency with the higher version. This commit updates the Gradle plugin to only include the runtime configuration's resolved dependencies during repackaging. As explained above, the runtime configuration extends the compile configuration so any compile dependencies will still be included, with the added benefit that duplicate versions of the same dependency will have been resolved to a single, preferred version. Closes gh-5749 --- .../gradle/MixedVersionRepackagingTests.java | 83 +++++++++++++++++++ .../mixed-version-repackaging.gradle | 30 +++++++ .../gradle/repackage/ProjectLibraries.java | 4 - 3 files changed, 113 insertions(+), 4 deletions(-) create mode 100644 spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/MixedVersionRepackagingTests.java create mode 100644 spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/mixed-version-repackaging.gradle diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/MixedVersionRepackagingTests.java b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/MixedVersionRepackagingTests.java new file mode 100644 index 0000000000..394176375c --- /dev/null +++ b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/MixedVersionRepackagingTests.java @@ -0,0 +1,83 @@ +/* + * Copyright 2012-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.gradle; + +import java.io.File; +import java.io.IOException; +import java.util.jar.JarFile; + +import org.assertj.core.api.Condition; +import org.assertj.core.description.TextDescription; +import org.gradle.tooling.ProjectConnection; +import org.junit.BeforeClass; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.not; + +/** + * Integration tests for Gradle repackaging with two different versions of the same + * dependency. + * + * @author Andy Wilkinson + */ +public class MixedVersionRepackagingTests { + + private static final String BOOT_VERSION = Versions.getBootVersion(); + + private static ProjectConnection project; + + @BeforeClass + public static void createProject() throws IOException { + project = new ProjectCreator().createProject("mixed-version-repackaging"); + } + + @Test + public void singleVersionIsIncludedInJar() throws IOException { + project.newBuild().forTasks("clean", "build") + .withArguments("-PbootVersion=" + BOOT_VERSION, "-Prepackage=true", + "-PexcludeDevtools=false") + .run(); + File buildLibs = new File("target/mixed-version-repackaging/build/libs"); + File repackageFile = new File(buildLibs, "mixed-version-repackaging.jar"); + assertThat(repackageFile.exists()).isTrue(); + assertThat(new JarFile(repackageFile)) + .has(entryNamed("BOOT-INF/lib/guava-18.0.jar")); + assertThat(new JarFile(repackageFile)) + .has(not(entryNamed("BOOT-INF/lib/guava-16.0.jar"))); + } + + private Condition entryNamed(String name) { + return new JarFileEntryCondition(name); + } + + private final class JarFileEntryCondition extends Condition { + + private final String entryName; + + private JarFileEntryCondition(String entryName) { + super(new TextDescription("entry named '%s'", entryName)); + this.entryName = entryName; + } + + @Override + public boolean matches(JarFile jarFile) { + return jarFile.getEntry(this.entryName) != null; + } + } + +} diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/mixed-version-repackaging.gradle b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/mixed-version-repackaging.gradle new file mode 100644 index 0000000000..9fb72c1c14 --- /dev/null +++ b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/mixed-version-repackaging.gradle @@ -0,0 +1,30 @@ +buildscript { + repositories { + mavenLocal() + mavenCentral() + } + dependencies { + classpath "org.springframework.boot:spring-boot-gradle-plugin:${project.bootVersion}" + } +} + +repositories { + mavenLocal() + mavenCentral() +} + +apply plugin: 'spring-boot' +apply plugin: 'java' + +dependencies { + compile 'com.google.guava:guava:16.0' + runtime 'com.google.guava:guava:18.0' +} + +dependencyManagement { + overriddenByDependencies = false +} + +springBoot { + mainClass = 'foo.bar.Baz' +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/repackage/ProjectLibraries.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/repackage/ProjectLibraries.java index 2c82f06fd5..db01938f5f 100644 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/repackage/ProjectLibraries.java +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/repackage/ProjectLibraries.java @@ -87,16 +87,12 @@ class ProjectLibraries implements Libraries { libraries(custom, callback); } else { - Set compile = getLibraries("compile", LibraryScope.COMPILE); Set runtime = getLibraries("runtime", LibraryScope.RUNTIME); - runtime = minus(runtime, compile); Set provided = getLibraries(this.providedConfigurationName, LibraryScope.PROVIDED); if (provided != null) { - compile = minus(compile, provided); runtime = minus(runtime, provided); } - libraries(compile, callback); libraries(runtime, callback); libraries(provided, callback); }