Skip to content

Commit

Permalink
Merge branch '2.2.x'
Browse files Browse the repository at this point in the history
Closes gh-18957
  • Loading branch information
wilkinsona committed Nov 11, 2019
2 parents a933e08 + 379ba0d commit b9f4a9c
Show file tree
Hide file tree
Showing 12 changed files with 134 additions and 29 deletions.
Expand Up @@ -41,7 +41,7 @@ Explicit build support is provided for the following build tools:
| 3.3+

| Gradle
| 5.x (4.10 is also supported but in a deprecated form)
| 5.x and 6.x (4.10 is also supported but in a deprecated form)
|===


Expand Down Expand Up @@ -195,7 +195,7 @@ In those cases, see <<using-spring-boot.adoc#using-boot-maven-without-a-parent>>

[[getting-started-gradle-installation]]
==== Gradle Installation
Spring Boot is compatible with 5.x.
Spring Boot is compatible with 5.x and 6.x.
4.10 is also supported but this support is deprecated and will be removed in a future release.
If you do not already have Gradle installed, you can follow the instructions at https://gradle.org.

Expand Down
Expand Up @@ -38,7 +38,7 @@ Andy Wilkinson

The Spring Boot Gradle Plugin provides Spring Boot support in https://gradle.org[Gradle].
It allows you to package executable jar or war archives, run Spring Boot applications, and use the dependency management provided by `spring-boot-dependencies`.
Spring Boot's Gradle plugin requires Gradle 5.x (4.10 is also supported but this support is deprecated and will be removed in a future release).
Spring Boot's Gradle plugin requires Gradle 5.x or 6.x (4.10 is also supported but this support is deprecated and will be removed in a future release).

In addition to this user guide, {api-documentation}[API documentation] is also available.

Expand Down
Expand Up @@ -49,4 +49,4 @@ include::../gradle/publishing/maven-publish.gradle.kts[tags=publishing]
When the {application-plugin}[`application` plugin] is applied a distribution named `boot` is created.
This distribution contains the archive produced by the `bootJar` or `bootWar` task and scripts to launch it on Unix-like platforms and Windows.
Zip and tar distributions can be built by the `bootDistZip` and `bootDistTar` tasks respectively.
To use the `application` plugin, its `mainClassName` project property must be configured with the name of your application's main class.
To use the `application` plugin, its `mainClassName` property must be configured with the name of your application's main class.
Expand Up @@ -60,7 +60,7 @@ include::../gradle/running/boot-run-disable-optimized-launch.gradle.kts[tags=lau
----


If the {application-plugin}[`application` plugin] has been applied, its `mainClassName` project property must be configured and can be used for the same purpose:
If the {application-plugin}[`application` plugin] has been applied, its `mainClassName` property must be configured and can be used for the same purpose:

[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
.Groovy
Expand Down
Expand Up @@ -5,7 +5,9 @@ plugins {
}

// tag::main-class[]
mainClassName = 'com.example.ExampleApplication'
application {
mainClassName = 'com.example.ExampleApplication'
}
// end::main-class[]

task configuredMainClass {
Expand Down
Expand Up @@ -17,13 +17,15 @@
package org.springframework.boot.gradle.dsl;

import java.io.File;
import java.lang.reflect.Method;

import org.gradle.api.Action;
import org.gradle.api.Project;
import org.gradle.api.plugins.BasePlugin;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.plugins.JavaPluginConvention;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.bundling.AbstractArchiveTask;
import org.gradle.jvm.tasks.Jar;

import org.springframework.boot.gradle.tasks.buildinfo.BuildInfo;
Expand Down Expand Up @@ -115,7 +117,7 @@ private File determineMainSourceSetResourcesOutputDir() {

private String determineArtifactBaseName() {
Jar artifactTask = findArtifactTask();
return (artifactTask != null) ? artifactTask.getBaseName() : null;
return (artifactTask != null) ? getArchiveBaseName(artifactTask) : null;
}

private Jar findArtifactTask() {
Expand All @@ -126,4 +128,26 @@ private Jar findArtifactTask() {
return (Jar) this.project.getTasks().findByName("bootJar");
}

private static String getArchiveBaseName(AbstractArchiveTask task) {
try {
Method method = findMethod(task.getClass(), "getArchiveBaseName");
if (method != null) {
return (String) method.invoke(task);
}
}
catch (Exception ex) {
// Continue
}
return task.getBaseName();
}

private static Method findMethod(Class<?> type, String name) {
for (Method candidate : type.getMethods()) {
if (candidate.getName().equals(name)) {
return candidate;
}
}
return null;
}

}
Expand Up @@ -20,6 +20,7 @@
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;

import org.gradle.api.GradleException;
Expand All @@ -32,6 +33,8 @@
import org.gradle.api.internal.IConventionAware;
import org.gradle.api.plugins.ApplicationPlugin;
import org.gradle.api.plugins.ApplicationPluginConvention;
import org.gradle.api.provider.Property;
import org.gradle.api.provider.Provider;
import org.gradle.jvm.application.scripts.TemplateBasedScriptGenerator;

import org.springframework.boot.gradle.tasks.application.CreateBootStartScripts;
Expand All @@ -49,10 +52,7 @@ public void execute(Project project) {
.getPlugin(ApplicationPluginConvention.class);
DistributionContainer distributions = project.getExtensions().getByType(DistributionContainer.class);
Distribution distribution = distributions.create("boot");
if (distribution instanceof IConventionAware) {
((IConventionAware) distribution).getConventionMapping().map("baseName",
() -> applicationConvention.getApplicationName() + "-boot");
}
configureBaseNameConvention(project, applicationConvention, distribution);
CreateBootStartScripts bootStartScripts = project.getTasks().create("bootStartScripts",
CreateBootStartScripts.class);
bootStartScripts
Expand All @@ -79,6 +79,37 @@ public void execute(Project project) {
distribution.getContents().with(binCopySpec);
}

@SuppressWarnings("unchecked")
private void configureBaseNameConvention(Project project, ApplicationPluginConvention applicationConvention,
Distribution distribution) {
Method getDistributionBaseName = findMethod(distribution.getClass(), "getDistributionBaseName");
if (getDistributionBaseName != null) {
try {
Property<String> distributionBaseName = (Property<String>) distribution.getClass()
.getMethod("getDistributionBaseName").invoke(distribution);
distributionBaseName.getClass().getMethod("convention", Provider.class).invoke(distributionBaseName,
project.provider(() -> applicationConvention.getApplicationName() + "-boot"));
return;
}
catch (Exception ex) {
// Continue
}
}
if (distribution instanceof IConventionAware) {
((IConventionAware) distribution).getConventionMapping().map("baseName",
() -> applicationConvention.getApplicationName() + "-boot");
}
}

private static Method findMethod(Class<?> type, String name) {
for (Method candidate : type.getMethods()) {
if (candidate.getName().equals(name)) {
return candidate;
}
}
return null;
}

@Override
public Class<? extends Plugin<Project>> getPluginClass() {
return ApplicationPlugin.class;
Expand Down
Expand Up @@ -25,6 +25,7 @@
import org.gradle.api.InvalidUserDataException;
import org.gradle.api.Project;
import org.gradle.api.file.FileCollection;
import org.gradle.api.plugins.JavaApplication;

import org.springframework.boot.gradle.dsl.SpringBootExtension;
import org.springframework.boot.loader.tools.MainClassFinder;
Expand Down Expand Up @@ -53,11 +54,9 @@ public Object call() throws Exception {
if (springBootExtension != null && springBootExtension.getMainClassName() != null) {
return springBootExtension.getMainClassName();
}
if (this.project.hasProperty("mainClassName")) {
Object mainClassName = this.project.property("mainClassName");
if (mainClassName != null) {
return mainClassName;
}
JavaApplication javaApplication = this.project.getConvention().findByType(JavaApplication.class);
if (javaApplication != null && javaApplication.getMainClassName() != null) {
return javaApplication.getMainClassName();
}
return resolveMainClass();
}
Expand Down
Expand Up @@ -20,6 +20,7 @@
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
Expand All @@ -37,6 +38,7 @@
import org.gradle.api.specs.Spec;
import org.gradle.api.specs.Specs;
import org.gradle.api.tasks.WorkResult;
import org.gradle.api.tasks.bundling.AbstractArchiveTask;
import org.gradle.api.tasks.bundling.Jar;
import org.gradle.api.tasks.util.PatternSet;

Expand Down Expand Up @@ -93,7 +95,7 @@ private String determineSpringBootVersion() {
}

CopyAction createCopyAction(Jar jar) {
CopyAction copyAction = new BootZipCopyAction(jar.getArchivePath(), jar.isPreserveFileTimestamps(),
CopyAction copyAction = new BootZipCopyAction(getOutputLocation(jar), jar.isPreserveFileTimestamps(),
isUsingDefaultLoader(jar), this.requiresUnpack.getAsSpec(), this.exclusions.getAsExcludeSpec(),
this.launchScript, this.compressionResolver, jar.getMetadataCharset());
if (!jar.isReproducibleFileOrder()) {
Expand All @@ -102,6 +104,28 @@ CopyAction createCopyAction(Jar jar) {
return new ReproducibleOrderingCopyAction(copyAction);
}

private static File getOutputLocation(AbstractArchiveTask task) {
try {
Method method = findMethod(task.getClass(), "getArchiveFile");
if (method != null) {
return (File) method.invoke(task);
}
}
catch (Exception ex) {
// Continue
}
return task.getArchivePath();
}

private static Method findMethod(Class<?> type, String name) {
for (Method candidate : type.getMethods()) {
if (candidate.getName().equals(name)) {
return candidate;
}
}
return null;
}

private boolean isUsingDefaultLoader(Jar jar) {
return DEFAULT_LAUNCHER_CLASSES.contains(jar.getManifest().getAttributes().get("Main-Class"));
}
Expand Down
Expand Up @@ -19,6 +19,7 @@
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
Expand Down Expand Up @@ -50,11 +51,32 @@ public LaunchScriptConfiguration() {

LaunchScriptConfiguration(AbstractArchiveTask archiveTask) {
Project project = archiveTask.getProject();
putIfMissing(this.properties, "initInfoProvides", archiveTask.getBaseName());
putIfMissing(this.properties, "initInfoShortDescription", removeLineBreaks(project.getDescription()),
archiveTask.getBaseName());
putIfMissing(this.properties, "initInfoDescription", augmentLineBreaks(project.getDescription()),
archiveTask.getBaseName());
String baseName = getArchiveBaseName(archiveTask);
putIfMissing(this.properties, "initInfoProvides", baseName);
putIfMissing(this.properties, "initInfoShortDescription", removeLineBreaks(project.getDescription()), baseName);
putIfMissing(this.properties, "initInfoDescription", augmentLineBreaks(project.getDescription()), baseName);
}

private static String getArchiveBaseName(AbstractArchiveTask task) {
try {
Method method = findMethod(task.getClass(), "getArchiveBaseName");
if (method != null) {
return (String) method.invoke(task);
}
}
catch (Exception ex) {
// Continue
}
return task.getBaseName();
}

private static Method findMethod(Class<?> type, String name) {
for (Method candidate : type.getMethods()) {
if (candidate.getName().equals(name)) {
return candidate;
}
}
return null;
}

/**
Expand Down
Expand Up @@ -39,7 +39,7 @@
public final class GradleCompatibilityExtension implements TestTemplateInvocationContextProvider {

private static final List<String> GRADLE_VERSIONS = Arrays.asList("default", "5.0", "5.1.1", "5.2.1", "5.3.1",
"5.4.1", "5.5.1", "5.6.4");
"5.4.1", "5.5.1", "5.6.4", "6.0");

@Override
public Stream<TestTemplateInvocationContext> provideTestTemplateInvocationContexts(ExtensionContext context) {
Expand Down
Expand Up @@ -20,7 +20,8 @@
import java.io.IOException;

import org.gradle.api.Project;
import org.gradle.api.plugins.ExtraPropertiesExtension;
import org.gradle.api.plugins.ApplicationPlugin;
import org.gradle.api.plugins.JavaApplication;
import org.gradle.testfixtures.ProjectBuilder;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -51,9 +52,10 @@ void createConvention() throws IOException {
}

@Test
void mainClassNameProjectPropertyIsUsed() throws Exception {
this.project.getExtensions().getByType(ExtraPropertiesExtension.class).set("mainClassName",
"com.example.MainClass");
void javaApplicationExtensionMainClassNameIsUsed() throws Exception {
this.project.getPlugins().apply(ApplicationPlugin.class);
JavaApplication extension = this.project.getExtensions().findByType(JavaApplication.class);
extension.setMainClassName("com.example.MainClass");
assertThat(this.convention.call()).isEqualTo("com.example.MainClass");
}

Expand All @@ -67,8 +69,9 @@ void springBootExtensionMainClassNameIsUsed() throws Exception {

@Test
void springBootExtensionMainClassNameIsUsedInPreferenceToMainClassNameProjectProperty() throws Exception {
this.project.getExtensions().getByType(ExtraPropertiesExtension.class).set("mainClassName",
"com.example.ProjectPropertyMainClass");
this.project.getPlugins().apply(ApplicationPlugin.class);
JavaApplication javaApplication = this.project.getExtensions().findByType(JavaApplication.class);
javaApplication.setMainClassName("com.example.JavaApplicationMainClass");
SpringBootExtension extension = this.project.getExtensions().create("springBoot", SpringBootExtension.class,
this.project);
extension.setMainClassName("com.example.SpringBootExtensionMainClass");
Expand Down

0 comments on commit b9f4a9c

Please sign in to comment.