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 fd9ee0edd21..93b2172a4a7 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; @@ -275,18 +273,21 @@ final class JavaPluginAction implements PluginApplicationAction { .ifPresent((locations) -> compile.doFirst(new AdditionalMetadataLocationsConfigurer(locations))); } + @SuppressWarnings({ "rawtypes", "unchecked" }) private void configureProductionRuntimeClasspathConfiguration(Project project) { 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.setVisible(false); Configuration runtimeClasspath = project.getConfigurations() .getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME); + 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.setExtendsFrom(runtimeClasspath.getExtendsFrom()); productionRuntimeClasspath.setCanBeResolved(runtimeClasspath.isCanBeResolved()); productionRuntimeClasspath.setCanBeConsumed(runtimeClasspath.isCanBeConsumed()); 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 d630e687d2d..3c97cff173e 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; @@ -191,11 +193,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