From b01235e68d42c4365ff342139565d7258facc97e Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 6 Nov 2023 11:50:27 +0000 Subject: [PATCH] Copy attributes from runtimeClasspath to productionRuntimeClasspath Fixes gh-38209 --- .../boot/gradle/plugin/JavaPluginAction.java | 21 +++++++++--------- .../JavaPluginActionIntegrationTests.java | 13 ++++++----- ...ClasspathIsConfiguredWithAttributes.gradle | 16 -------------- ...AttributesThatMatchRuntimeClasspath.gradle | 22 +++++++++++++++++++ 4 files changed, 41 insertions(+), 31 deletions(-) delete mode 100644 spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests-productionRuntimeClasspathIsConfiguredWithAttributes.gradle create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests-productionRuntimeClasspathIsConfiguredWithAttributesThatMatchRuntimeClasspath.gradle diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/JavaPluginAction.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/JavaPluginAction.java index 94565760524..c6ad89c5eb3 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/JavaPluginAction.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/JavaPluginAction.java @@ -26,12 +26,9 @@ import org.gradle.api.Plugin; import org.gradle.api.Project; import org.gradle.api.Task; import org.gradle.api.artifacts.Configuration; +import org.gradle.api.attributes.Attribute; import org.gradle.api.attributes.AttributeContainer; -import org.gradle.api.attributes.Bundling; -import org.gradle.api.attributes.LibraryElements; -import org.gradle.api.attributes.Usage; import org.gradle.api.file.FileCollection; -import org.gradle.api.model.ObjectFactory; import org.gradle.api.plugins.ApplicationPlugin; import org.gradle.api.plugins.BasePlugin; import org.gradle.api.plugins.ExtensionContainer; @@ -39,6 +36,7 @@ import org.gradle.api.plugins.JavaApplication; import org.gradle.api.plugins.JavaPlugin; import org.gradle.api.plugins.JavaPluginExtension; import org.gradle.api.provider.Provider; +import org.gradle.api.provider.ProviderFactory; import org.gradle.api.tasks.SourceSet; import org.gradle.api.tasks.SourceSetContainer; import org.gradle.api.tasks.TaskProvider; @@ -270,6 +268,7 @@ final class JavaPluginAction implements PluginApplicationAction { .ifPresent((locations) -> compile.doFirst(new AdditionalMetadataLocationsConfigurer(locations))); } + @SuppressWarnings({ "rawtypes", "unchecked" }) private void configureDevelopmentOnlyConfiguration(Project project) { Configuration developmentOnly = project.getConfigurations() .create(SpringBootPlugin.DEVELOPMENT_ONLY_CONFIGURATION_NAME); @@ -279,12 +278,14 @@ final class JavaPluginAction implements PluginApplicationAction { .getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME); Configuration productionRuntimeClasspath = project.getConfigurations() .create(SpringBootPlugin.PRODUCTION_RUNTIME_CLASSPATH_CONFIGURATION_NAME); - AttributeContainer attributes = productionRuntimeClasspath.getAttributes(); - ObjectFactory objectFactory = project.getObjects(); - attributes.attribute(Usage.USAGE_ATTRIBUTE, objectFactory.named(Usage.class, Usage.JAVA_RUNTIME)); - attributes.attribute(Bundling.BUNDLING_ATTRIBUTE, objectFactory.named(Bundling.class, Bundling.EXTERNAL)); - attributes.attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, - objectFactory.named(LibraryElements.class, LibraryElements.JAR)); + productionRuntimeClasspath.attributes((attributes) -> { + ProviderFactory providers = project.getProviders(); + AttributeContainer sourceAttributes = runtimeClasspath.getAttributes(); + for (Attribute attribute : sourceAttributes.keySet()) { + attributes.attributeProvider(attribute, + providers.provider(() -> sourceAttributes.getAttribute(attribute))); + } + }); productionRuntimeClasspath.setVisible(false); productionRuntimeClasspath.setExtendsFrom(runtimeClasspath.getExtendsFrom()); productionRuntimeClasspath.setCanBeResolved(runtimeClasspath.isCanBeResolved()); diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests.java index 0b62f88b5d5..a9fdff46ee7 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests.java @@ -24,6 +24,8 @@ import java.io.StringReader; import java.util.HashSet; import java.util.Set; import java.util.jar.JarOutputStream; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.gradle.testkit.runner.BuildResult; import org.gradle.testkit.runner.TaskOutcome; @@ -146,11 +148,12 @@ class JavaPluginActionIntegrationTests { } @TestTemplate - void productionRuntimeClasspathIsConfiguredWithAttributes() { - assertThat(this.gradleBuild.build("build").getOutput()).contains("3 productionRuntimeClasspath attributes:") - .contains("org.gradle.usage: java-runtime") - .contains("org.gradle.libraryelements: jar") - .contains("org.gradle.dependency.bundling: external"); + void productionRuntimeClasspathIsConfiguredWithAttributesThatMatchRuntimeClasspath() { + String output = this.gradleBuild.build("build").getOutput(); + Matcher matcher = Pattern.compile("runtimeClasspath: (\\[.*\\])").matcher(output); + assertThat(matcher.find()).as("%s found in %s", matcher, output).isTrue(); + String attributes = matcher.group(1); + assertThat(output).contains("productionRuntimeClasspath: " + attributes); } @TestTemplate diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests-productionRuntimeClasspathIsConfiguredWithAttributes.gradle b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests-productionRuntimeClasspathIsConfiguredWithAttributes.gradle deleted file mode 100644 index c4ccd15df3a..00000000000 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests-productionRuntimeClasspathIsConfiguredWithAttributes.gradle +++ /dev/null @@ -1,16 +0,0 @@ -plugins { - id 'org.springframework.boot' version '{version}' - id 'java' -} - -springBoot { - mainClass = "com.example.Main" -} - -gradle.taskGraph.whenReady { - def attributes = configurations.findByName('productionRuntimeClasspath').attributes - println "${attributes.keySet().size()} productionRuntimeClasspath attributes:" - attributes.keySet().each { attribute -> - println " ${attribute}: ${attributes.getAttribute(attribute)}" - } -} \ No newline at end of file diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests-productionRuntimeClasspathIsConfiguredWithAttributesThatMatchRuntimeClasspath.gradle b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests-productionRuntimeClasspathIsConfiguredWithAttributesThatMatchRuntimeClasspath.gradle new file mode 100644 index 00000000000..7f0744a6184 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests-productionRuntimeClasspathIsConfiguredWithAttributesThatMatchRuntimeClasspath.gradle @@ -0,0 +1,22 @@ +def collectAttributes(String configurationName) { + def attributes = configurations.findByName(configurationName).attributes + def keys = new TreeSet<>((a1, a2) -> a1.name.compareTo(a2.name)) + keys.addAll(attributes.keySet()) + keys.collect { key -> "${key}: ${attributes.getAttribute(key)}" } +} + +plugins { + id 'org.springframework.boot' version '{version}' + id 'java' +} + +springBoot { + mainClass = "com.example.Main" +} + +gradle.taskGraph.whenReady { + def runtimeClasspathAttributes = collectAttributes("runtimeClasspath") + def productionRuntimeClasspathAttributes = collectAttributes("productionRuntimeClasspath") + println("runtimeClasspath: ${runtimeClasspathAttributes}") + println("productionRuntimeClasspath: ${productionRuntimeClasspathAttributes}") +} \ No newline at end of file