From 884cae6f8d0d75e4f108e1c0e51cdf4747667199 Mon Sep 17 00:00:00 2001 From: Vedran Pavic Date: Tue, 24 Nov 2015 22:05:32 +0100 Subject: [PATCH] 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 --- .../main/asciidoc/spring-boot-features.adoc | 7 ++- .../springframework/boot/ResourceBanner.java | 17 ++++++++ .../boot/ResourceBannerTests.java | 43 +++++++++++++++---- 3 files changed, 57 insertions(+), 10 deletions(-) diff --git a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 622cdcbbcd2..42289ac18ad 100644 --- a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -60,7 +60,8 @@ You can use the following variables inside your `banner.txt` file: | Variable | Description |`${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}` |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}`) |Where `NAME` is the name of an ANSI escape code. See {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 diff --git a/spring-boot/src/main/java/org/springframework/boot/ResourceBanner.java b/spring-boot/src/main/java/org/springframework/boot/ResourceBanner.java index 8db7b5465fd..901d3dbfd02 100644 --- a/spring-boot/src/main/java/org/springframework/boot/ResourceBanner.java +++ b/spring-boot/src/main/java/org/springframework/boot/ResourceBanner.java @@ -19,6 +19,7 @@ package org.springframework.boot; import java.io.PrintStream; import java.nio.charset.Charset; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -40,6 +41,7 @@ import org.springframework.util.StreamUtils; * Banner implementation that prints from a source {@link Resource}. * * @author Phillip Webb + * @author Vedran Pavic * @since 1.2.0 */ public class ResourceBanner implements Banner { @@ -80,6 +82,7 @@ public class ResourceBanner implements Banner { resolvers.add(environment); resolvers.add(getVersionResolver(sourceClass)); resolvers.add(getAnsiResolver()); + resolvers.add(getTitleResolver(sourceClass)); return resolvers; } @@ -124,4 +127,18 @@ public class ResourceBanner implements Banner { return new PropertySourcesPropertyResolver(sources); } + private PropertyResolver getTitleResolver(Class sourceClass) { + MutablePropertySources sources = new MutablePropertySources(); + String applicationTitle = getApplicationTitle(sourceClass); + Map titleMap = Collections.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()); + } + } diff --git a/spring-boot/src/test/java/org/springframework/boot/ResourceBannerTests.java b/spring-boot/src/test/java/org/springframework/boot/ResourceBannerTests.java index d19a759b420..423cfea901f 100644 --- a/spring-boot/src/test/java/org/springframework/boot/ResourceBannerTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/ResourceBannerTests.java @@ -39,6 +39,7 @@ import static org.junit.Assert.assertThat; * Tests for {@link ResourceBanner}. * * @author Phillip Webb + * @author Vedran Pavic */ public class ResourceBannerTests { @@ -51,7 +52,7 @@ public class ResourceBannerTests { public void renderVersions() throws Exception { Resource resource = new ByteArrayResource( "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")); } @@ -59,7 +60,7 @@ public class ResourceBannerTests { public void renderWithoutVersions() throws Exception { Resource resource = new ByteArrayResource( "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 ")); } @@ -68,7 +69,7 @@ public class ResourceBannerTests { Resource resource = new ByteArrayResource( "banner ${a}${spring-boot.formatted-version}${application.formatted-version}" .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)")); } @@ -77,7 +78,7 @@ public class ResourceBannerTests { Resource resource = new ByteArrayResource( "banner ${a}${spring-boot.formatted-version}${application.formatted-version}" .getBytes()); - String banner = printBanner(resource, null, null); + String banner = printBanner(resource, null, null, null); assertThat(banner, startsWith("banner 1")); } @@ -86,7 +87,7 @@ public class ResourceBannerTests { Resource resource = new ByteArrayResource( "${Ansi.RED}This is red.${Ansi.NORMAL}".getBytes()); 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")); } @@ -95,14 +96,30 @@ public class ResourceBannerTests { Resource resource = new ByteArrayResource( "${Ansi.RED}This is red.${Ansi.NORMAL}".getBytes()); AnsiOutput.setEnabled(AnsiOutput.Enabled.NEVER); - String banner = printBanner(resource, null, null); + String banner = printBanner(resource, null, null, null); 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, - String applicationVersion) { + String applicationVersion, String applicationTitle) { ResourceBanner banner = new MockResourceBanner(resource, bootVersion, - applicationVersion); + applicationVersion, applicationTitle); ConfigurableEnvironment environment = new MockEnvironment(); Map source = Collections.singletonMap("a", "1"); environment.getPropertySources().addLast(new MapPropertySource("map", source)); @@ -117,11 +134,14 @@ public class ResourceBannerTests { private final String applicationVersion; + private final String applicationTitle; + MockResourceBanner(Resource resource, String bootVersion, - String applicationVersion) { + String applicationVersion, String applicationTitle) { super(resource); this.bootVersion = bootVersion; this.applicationVersion = applicationVersion; + this.applicationTitle = applicationTitle; } @Override @@ -134,6 +154,11 @@ public class ResourceBannerTests { return this.applicationVersion; } + @Override + protected String getApplicationTitle(Class sourceClass) { + return this.applicationTitle; + } + } }