From a707c5e83e479099f8dd71fb06806e143efdd119 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Mon, 24 Apr 2023 17:15:56 -0700 Subject: [PATCH] Polish "Fix support for default values in banner placeholders" Reorder methods and add a test to ensure that getPropertyResolvers can be mutated. See gh-34764 --- .../springframework/boot/ResourceBanner.java | 61 ++++++++++++------- .../boot/ResourceBannerTests.java | 47 +++++++++++++- 2 files changed, 84 insertions(+), 24 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/ResourceBanner.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/ResourceBanner.java index 46108497dfa..68867dec2c4 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/ResourceBanner.java +++ b/spring-boot-project/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.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -65,7 +66,6 @@ public class ResourceBanner implements Banner { try { String banner = StreamUtils.copyToString(this.resource.getInputStream(), environment.getProperty("spring.banner.charset", Charset.class, StandardCharsets.UTF_8)); - for (PropertyResolver resolver : getPropertyResolvers(environment, sourceClass)) { banner = resolver.resolvePlaceholders(banner); } @@ -77,15 +77,46 @@ public class ResourceBanner implements Banner { } } + /** + * Return a mutable list of the {@link PropertyResolver} instances that will be used + * to resolve placeholders. + * @param environment the environment + * @param sourceClass the source class + * @return a mutable list of property resolvers + */ protected List getPropertyResolvers(Environment environment, Class sourceClass) { - MutablePropertySources propertySources = new MutablePropertySources(); + MutablePropertySources sources = new MutablePropertySources(); if (environment instanceof ConfigurableEnvironment) { - ((ConfigurableEnvironment) environment).getPropertySources().forEach(propertySources::addLast); + ((ConfigurableEnvironment) environment).getPropertySources().forEach(sources::addLast); } - propertySources.addLast(getTitleSource(sourceClass)); - propertySources.addLast(getAnsiSource()); - propertySources.addLast(getVersionSource(sourceClass)); - return Collections.singletonList(new PropertySourcesPropertyResolver(propertySources)); + sources.addLast(getTitleSource(sourceClass)); + sources.addLast(getAnsiSource()); + sources.addLast(getVersionSource(sourceClass)); + List resolvers = new ArrayList<>(); + resolvers.add(new PropertySourcesPropertyResolver(sources)); + return resolvers; + } + + private MapPropertySource getTitleSource(Class sourceClass) { + String applicationTitle = getApplicationTitle(sourceClass); + Map titleMap = Collections.singletonMap("application.title", + (applicationTitle != null) ? applicationTitle : ""); + return new MapPropertySource("title", titleMap); + } + + /** + * Return the application title that should be used for the source class. By default + * will use {@link Package#getImplementationTitle()}. + * @param sourceClass the source class + * @return the application title + */ + protected String getApplicationTitle(Class sourceClass) { + Package sourcePackage = (sourceClass != null) ? sourceClass.getPackage() : null; + return (sourcePackage != null) ? sourcePackage.getImplementationTitle() : null; + } + + private AnsiPropertySource getAnsiSource() { + return new AnsiPropertySource("ansi", true); } private MapPropertySource getVersionSource(Class sourceClass) { @@ -119,20 +150,4 @@ public class ResourceBanner implements Banner { return format ? " (v" + version + ")" : version; } - private AnsiPropertySource getAnsiSource() { - return new AnsiPropertySource("ansi", true); - } - - private MapPropertySource getTitleSource(Class sourceClass) { - String applicationTitle = getApplicationTitle(sourceClass); - Map titleMap = Collections.singletonMap("application.title", - (applicationTitle != null) ? applicationTitle : ""); - return new MapPropertySource("title", titleMap); - } - - protected String getApplicationTitle(Class sourceClass) { - Package sourcePackage = (sourceClass != null) ? sourceClass.getPackage() : null; - return (sourcePackage != null) ? sourcePackage.getImplementationTitle() : null; - } - } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/ResourceBannerTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/ResourceBannerTests.java index 9960e78c9b8..8ba272032d4 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/ResourceBannerTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/ResourceBannerTests.java @@ -19,6 +19,7 @@ package org.springframework.boot; import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.util.Collections; +import java.util.List; import java.util.Map; import org.junit.jupiter.api.AfterEach; @@ -26,8 +27,11 @@ import org.junit.jupiter.api.Test; import org.springframework.boot.ansi.AnsiOutput; import org.springframework.boot.ansi.AnsiOutput.Enabled; +import org.springframework.core.env.AbstractPropertyResolver; import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.Environment; import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.PropertyResolver; import org.springframework.core.io.ByteArrayResource; import org.springframework.core.io.Resource; import org.springframework.mock.env.MockEnvironment; @@ -136,9 +140,20 @@ class ResourceBannerTests { assertThat(banner).startsWith("banner 1 default-b 10.2 1.0"); } + @Test + void renderWithMutation() { + Resource resource = new ByteArrayResource("banner ${foo}".getBytes()); + String banner = printBanner(new MutatingResourceBanner(resource, "1", "2", null)); + assertThat(banner).startsWith("banner bar"); + + } + private String printBanner(Resource resource, String bootVersion, String applicationVersion, String applicationTitle) { - ResourceBanner banner = new MockResourceBanner(resource, bootVersion, applicationVersion, applicationTitle); + return printBanner(new MockResourceBanner(resource, bootVersion, applicationVersion, applicationTitle)); + } + + private String printBanner(ResourceBanner banner) { ConfigurableEnvironment environment = new MockEnvironment(); Map source = Collections.singletonMap("a", "1"); environment.getPropertySources().addLast(new MapPropertySource("map", source)); @@ -179,4 +194,34 @@ class ResourceBannerTests { } + static class MutatingResourceBanner extends MockResourceBanner { + + MutatingResourceBanner(Resource resource, String bootVersion, String applicationVersion, + String applicationTitle) { + super(resource, bootVersion, applicationVersion, applicationTitle); + } + + @Override + protected List getPropertyResolvers(Environment environment, Class sourceClass) { + List resolvers = super.getPropertyResolvers(environment, sourceClass); + PropertyResolver resolver = new AbstractPropertyResolver() { + + @Override + @SuppressWarnings("unchecked") + public T getProperty(String key, Class targetType) { + return String.class.equals(targetType) ? (T) getPropertyAsRawString(key) : null; + } + + @Override + protected String getPropertyAsRawString(String key) { + return ("foo".equals(key)) ? "bar" : null; + } + + }; + resolvers.add(resolver); + return resolvers; + } + + } + }