Add support for using ${application.title} in startup banners

This commit introduces a new property, application.title, that can
be used in a banner. Its value is resolved from the application
manifest's Implementation-Title attribute.

Closes gh-4603
This commit is contained in:
Vedran Pavic 2015-11-24 22:05:32 +01:00 committed by Andy Wilkinson
parent a4baacc549
commit 884cae6f8d
3 changed files with 57 additions and 10 deletions

View File

@ -60,7 +60,8 @@ You can use the following variables inside your `banner.txt` file:
| Variable | Description | Variable | Description
|`${application.version}` |`${application.version}`
|The version number of your application as declared in `MANIFEST.MF`. For example `Implementation-Version: 1.0` is printed as `1.0`. |The version number of your application as declared in `MANIFEST.MF`. For example
`Implementation-Version: 1.0` is printed as `1.0`.
|`${application.formatted-version}` |`${application.formatted-version}`
|The version number of your application as declared in `MANIFEST.MF` formatted for |The version number of your application as declared in `MANIFEST.MF` formatted for
@ -76,6 +77,10 @@ brackets and prefixed with `v`). For example `(v{spring-boot-version})`.
|`${Ansi.NAME}` (or `${AnsiColor.NAME}`, `${AnsiBackground.NAME}`, `${AnsiStyle.NAME}`) |`${Ansi.NAME}` (or `${AnsiColor.NAME}`, `${AnsiBackground.NAME}`, `${AnsiStyle.NAME}`)
|Where `NAME` is the name of an ANSI escape code. See |Where `NAME` is the name of an ANSI escape code. See
{sc-spring-boot}/ansi/AnsiPropertySource.{sc-ext}[`AnsiPropertySource`] for details. {sc-spring-boot}/ansi/AnsiPropertySource.{sc-ext}[`AnsiPropertySource`] for details.
|`${application.title}`
|The title of your application as declared in `MANIFEST.MF`. For example
`Implementation-Title: MyApp` is printed as `MyApp`.
|=== |===
TIP: The `SpringApplication.setBanner(...)` method can be used if you want to generate TIP: The `SpringApplication.setBanner(...)` method can be used if you want to generate

View File

@ -19,6 +19,7 @@ package org.springframework.boot;
import java.io.PrintStream; import java.io.PrintStream;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -40,6 +41,7 @@ import org.springframework.util.StreamUtils;
* Banner implementation that prints from a source {@link Resource}. * Banner implementation that prints from a source {@link Resource}.
* *
* @author Phillip Webb * @author Phillip Webb
* @author Vedran Pavic
* @since 1.2.0 * @since 1.2.0
*/ */
public class ResourceBanner implements Banner { public class ResourceBanner implements Banner {
@ -80,6 +82,7 @@ public class ResourceBanner implements Banner {
resolvers.add(environment); resolvers.add(environment);
resolvers.add(getVersionResolver(sourceClass)); resolvers.add(getVersionResolver(sourceClass));
resolvers.add(getAnsiResolver()); resolvers.add(getAnsiResolver());
resolvers.add(getTitleResolver(sourceClass));
return resolvers; return resolvers;
} }
@ -124,4 +127,18 @@ public class ResourceBanner implements Banner {
return new PropertySourcesPropertyResolver(sources); return new PropertySourcesPropertyResolver(sources);
} }
private PropertyResolver getTitleResolver(Class<?> sourceClass) {
MutablePropertySources sources = new MutablePropertySources();
String applicationTitle = getApplicationTitle(sourceClass);
Map<String, Object> titleMap = Collections.<String, Object>singletonMap(
"application.title", (applicationTitle == null ? "" : applicationTitle));
sources.addFirst(new MapPropertySource("title", titleMap));
return new PropertySourcesPropertyResolver(sources);
}
protected String getApplicationTitle(Class<?> sourceClass) {
Package sourcePackage = (sourceClass == null ? null : sourceClass.getPackage());
return (sourcePackage == null ? null : sourcePackage.getImplementationTitle());
}
} }

View File

@ -39,6 +39,7 @@ import static org.junit.Assert.assertThat;
* Tests for {@link ResourceBanner}. * Tests for {@link ResourceBanner}.
* *
* @author Phillip Webb * @author Phillip Webb
* @author Vedran Pavic
*/ */
public class ResourceBannerTests { public class ResourceBannerTests {
@ -51,7 +52,7 @@ public class ResourceBannerTests {
public void renderVersions() throws Exception { public void renderVersions() throws Exception {
Resource resource = new ByteArrayResource( Resource resource = new ByteArrayResource(
"banner ${a} ${spring-boot.version} ${application.version}".getBytes()); "banner ${a} ${spring-boot.version} ${application.version}".getBytes());
String banner = printBanner(resource, "10.2", "2.0"); String banner = printBanner(resource, "10.2", "2.0", null);
assertThat(banner, startsWith("banner 1 10.2 2.0")); assertThat(banner, startsWith("banner 1 10.2 2.0"));
} }
@ -59,7 +60,7 @@ public class ResourceBannerTests {
public void renderWithoutVersions() throws Exception { public void renderWithoutVersions() throws Exception {
Resource resource = new ByteArrayResource( Resource resource = new ByteArrayResource(
"banner ${a} ${spring-boot.version} ${application.version}".getBytes()); "banner ${a} ${spring-boot.version} ${application.version}".getBytes());
String banner = printBanner(resource, null, null); String banner = printBanner(resource, null, null, null);
assertThat(banner, startsWith("banner 1 ")); assertThat(banner, startsWith("banner 1 "));
} }
@ -68,7 +69,7 @@ public class ResourceBannerTests {
Resource resource = new ByteArrayResource( Resource resource = new ByteArrayResource(
"banner ${a}${spring-boot.formatted-version}${application.formatted-version}" "banner ${a}${spring-boot.formatted-version}${application.formatted-version}"
.getBytes()); .getBytes());
String banner = printBanner(resource, "10.2", "2.0"); String banner = printBanner(resource, "10.2", "2.0", null);
assertThat(banner, startsWith("banner 1 (v10.2) (v2.0)")); assertThat(banner, startsWith("banner 1 (v10.2) (v2.0)"));
} }
@ -77,7 +78,7 @@ public class ResourceBannerTests {
Resource resource = new ByteArrayResource( Resource resource = new ByteArrayResource(
"banner ${a}${spring-boot.formatted-version}${application.formatted-version}" "banner ${a}${spring-boot.formatted-version}${application.formatted-version}"
.getBytes()); .getBytes());
String banner = printBanner(resource, null, null); String banner = printBanner(resource, null, null, null);
assertThat(banner, startsWith("banner 1")); assertThat(banner, startsWith("banner 1"));
} }
@ -86,7 +87,7 @@ public class ResourceBannerTests {
Resource resource = new ByteArrayResource( Resource resource = new ByteArrayResource(
"${Ansi.RED}This is red.${Ansi.NORMAL}".getBytes()); "${Ansi.RED}This is red.${Ansi.NORMAL}".getBytes());
AnsiOutput.setEnabled(AnsiOutput.Enabled.ALWAYS); AnsiOutput.setEnabled(AnsiOutput.Enabled.ALWAYS);
String banner = printBanner(resource, null, null); String banner = printBanner(resource, null, null, null);
assertThat(banner, startsWith("\u001B[31mThis is red.\u001B[0m")); assertThat(banner, startsWith("\u001B[31mThis is red.\u001B[0m"));
} }
@ -95,14 +96,30 @@ public class ResourceBannerTests {
Resource resource = new ByteArrayResource( Resource resource = new ByteArrayResource(
"${Ansi.RED}This is red.${Ansi.NORMAL}".getBytes()); "${Ansi.RED}This is red.${Ansi.NORMAL}".getBytes());
AnsiOutput.setEnabled(AnsiOutput.Enabled.NEVER); AnsiOutput.setEnabled(AnsiOutput.Enabled.NEVER);
String banner = printBanner(resource, null, null); String banner = printBanner(resource, null, null, null);
assertThat(banner, startsWith("This is red.")); assertThat(banner, startsWith("This is red."));
} }
@Test
public void renderWithTitle() throws Exception {
Resource resource = new ByteArrayResource(
"banner ${application.title} ${a}".getBytes());
String banner = printBanner(resource, null, null, "title");
assertThat(banner, startsWith("banner title 1"));
}
@Test
public void renderWithoutTitle() throws Exception {
Resource resource = new ByteArrayResource(
"banner ${application.title} ${a}".getBytes());
String banner = printBanner(resource, null, null, null);
assertThat(banner, startsWith("banner 1"));
}
private String printBanner(Resource resource, String bootVersion, private String printBanner(Resource resource, String bootVersion,
String applicationVersion) { String applicationVersion, String applicationTitle) {
ResourceBanner banner = new MockResourceBanner(resource, bootVersion, ResourceBanner banner = new MockResourceBanner(resource, bootVersion,
applicationVersion); applicationVersion, applicationTitle);
ConfigurableEnvironment environment = new MockEnvironment(); ConfigurableEnvironment environment = new MockEnvironment();
Map<String, Object> source = Collections.<String, Object>singletonMap("a", "1"); Map<String, Object> source = Collections.<String, Object>singletonMap("a", "1");
environment.getPropertySources().addLast(new MapPropertySource("map", source)); environment.getPropertySources().addLast(new MapPropertySource("map", source));
@ -117,11 +134,14 @@ public class ResourceBannerTests {
private final String applicationVersion; private final String applicationVersion;
private final String applicationTitle;
MockResourceBanner(Resource resource, String bootVersion, MockResourceBanner(Resource resource, String bootVersion,
String applicationVersion) { String applicationVersion, String applicationTitle) {
super(resource); super(resource);
this.bootVersion = bootVersion; this.bootVersion = bootVersion;
this.applicationVersion = applicationVersion; this.applicationVersion = applicationVersion;
this.applicationTitle = applicationTitle;
} }
@Override @Override
@ -134,6 +154,11 @@ public class ResourceBannerTests {
return this.applicationVersion; return this.applicationVersion;
} }
@Override
protected String getApplicationTitle(Class<?> sourceClass) {
return this.applicationTitle;
}
} }
} }