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 650003bc73..11d9991ed0 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
@@ -28,6 +28,7 @@ import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.springframework.boot.ansi.Ansi256PropertySource;
import org.springframework.boot.ansi.AnsiPropertySource;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MapPropertySource;
@@ -43,6 +44,7 @@ import org.springframework.util.StreamUtils;
*
* @author Phillip Webb
* @author Vedran Pavic
+ * @author Toshiaki Maki
* @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(getAnsi256Resolver());
resolvers.add(getTitleResolver(sourceClass));
return resolvers;
}
@@ -123,6 +126,12 @@ public class ResourceBanner implements Banner {
return new PropertySourcesPropertyResolver(sources);
}
+ private PropertyResolver getAnsi256Resolver() {
+ MutablePropertySources sources = new MutablePropertySources();
+ sources.addFirst(new Ansi256PropertySource("ansi256"));
+ return new PropertySourcesPropertyResolver(sources);
+ }
+
private PropertyResolver getTitleResolver(Class> sourceClass) {
MutablePropertySources sources = new MutablePropertySources();
String applicationTitle = getApplicationTitle(sourceClass);
diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/ansi/Ansi256Color.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/ansi/Ansi256Color.java
new file mode 100644
index 0000000000..e93f166602
--- /dev/null
+++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/ansi/Ansi256Color.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2012-2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.ansi;
+
+/**
+ * {@link AnsiElement} implementation for Ansi 256 colors.
+ *
+ * use {@link Ansi256Color.Foreground} or {@link Ansi256Color.Background} as a concrete
+ * class.
+ *
+ * @author Toshiaki Maki
+ * @since 2.2.0
+ */
+public abstract class Ansi256Color implements AnsiElement {
+
+ /**
+ * color code
+ */
+ final int colorCode;
+
+ /**
+ * @param colorCode color code (must be 0-255)
+ * @throws IllegalArgumentException if color code is not between 0 and 255.
+ */
+ Ansi256Color(int colorCode) {
+ if (colorCode < 0 || colorCode > 255) {
+ throw new IllegalArgumentException("'colorCode' must be between 0 and 255.");
+ }
+ this.colorCode = colorCode;
+ }
+
+ /**
+ * {@link Ansi256Color} foreground colors.
+ *
+ * @author Toshiaki Maki
+ * @since 2.2.0
+ */
+ public static class Foreground extends Ansi256Color {
+
+ public Foreground(int colorCode) {
+ super(colorCode);
+ }
+
+ @Override
+ public String toString() {
+ return "38;5;" + super.colorCode;
+ }
+
+ }
+
+ /**
+ * {@link Ansi256Color} background colors.
+ *
+ * @author Toshiaki Maki
+ * @since 2.2.0
+ */
+ public static class Background extends Ansi256Color {
+
+ public Background(int colorCode) {
+ super(colorCode);
+ }
+
+ @Override
+ public String toString() {
+ return "48;5;" + super.colorCode;
+ }
+
+ }
+
+}
diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/ansi/Ansi256PropertySource.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/ansi/Ansi256PropertySource.java
new file mode 100644
index 0000000000..0420d2de6e
--- /dev/null
+++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/ansi/Ansi256PropertySource.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2012-2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.ansi;
+
+import org.springframework.core.env.PropertyResolver;
+import org.springframework.core.env.PropertySource;
+import org.springframework.util.StringUtils;
+
+/**
+ * {@link PropertyResolver} for {@link Ansi256Color.Background} and
+ * {@link Ansi256Color.Foreground} elements. Supports properties of the form
+ * {@code Ansi256Color.Foreground_N} and {@code Ansi256Color.Background_N} ({@code N} must
+ * be between 0 and 255).
+ *
+ * @author Toshiaki Maki
+ * @since 2.2.0
+ */
+public class Ansi256PropertySource extends PropertySource {
+
+ private static final String PREFIX = "Ansi256Color.";
+
+ private static final String FOREGROUND_PREFIX = PREFIX + "Foreground_";
+
+ private static final String BACKGROUND_PREFIX = PREFIX + "Background_";
+
+ /**
+ * Create a new {@link Ansi256PropertySource} instance.
+ * @param name the name of the property source
+ */
+ public Ansi256PropertySource(String name) {
+ super(name);
+ }
+
+ @Override
+ public Object getProperty(String name) {
+ if (StringUtils.hasLength(name)) {
+ if (name.startsWith(FOREGROUND_PREFIX)) {
+ final int colorCode = Integer.parseInt(name.substring(FOREGROUND_PREFIX.length()));
+ return AnsiOutput.encode(new Ansi256Color.Foreground(colorCode));
+ }
+ else if (name.startsWith(BACKGROUND_PREFIX)) {
+ final int colorCode = Integer.parseInt(name.substring(BACKGROUND_PREFIX.length()));
+ return AnsiOutput.encode(new Ansi256Color.Background(colorCode));
+ }
+ }
+ return 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 d75d3474bd..39234e5bd7 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
@@ -39,6 +39,7 @@ import static org.assertj.core.api.Assertions.assertThat;
*
* @author Phillip Webb
* @author Vedran Pavic
+ * @author Toshiaki Maki
*/
class ResourceBannerTests {
@@ -95,6 +96,24 @@ class ResourceBannerTests {
assertThat(banner).startsWith("This is red.");
}
+ @Test
+ void renderWith256Colors() {
+ Resource resource = new ByteArrayResource(
+ "${Ansi256Color.Foreground_208}This is orange.${Ansi.NORMAL}".getBytes());
+ AnsiOutput.setEnabled(AnsiOutput.Enabled.ALWAYS);
+ String banner = printBanner(resource, null, null, null);
+ assertThat(banner).startsWith("\033[38;5;208mThis is orange.\u001B[0m");
+ }
+
+ @Test
+ void renderWith256ColorsButDisabled() {
+ Resource resource = new ByteArrayResource(
+ "${Ansi256Color.Foreground_208}This is orange.${Ansi.NORMAL}".getBytes());
+ AnsiOutput.setEnabled(AnsiOutput.Enabled.NEVER);
+ String banner = printBanner(resource, null, null, null);
+ assertThat(banner).startsWith("This is orange.");
+ }
+
@Test
void renderWithTitle() {
Resource resource = new ByteArrayResource("banner ${application.title} ${a}".getBytes());
diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/ansi/Ansi256ColorTest.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/ansi/Ansi256ColorTest.java
new file mode 100644
index 0000000000..bc32ea9c6f
--- /dev/null
+++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/ansi/Ansi256ColorTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2012-2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.ansi;
+
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown;
+
+/**
+ * Tests for {@link Ansi256Color}.
+ *
+ * @author Toshiaki Maki
+ */
+class Ansi256ColorTest {
+
+ @Test
+ void testForeground() {
+ final Ansi256Color ansi256Color = new Ansi256Color.Foreground(208);
+ assertThat(ansi256Color.toString()).isEqualTo("38;5;208");
+ }
+
+ @Test
+ void testBackground() {
+ final Ansi256Color ansi256Color = new Ansi256Color.Background(208);
+ assertThat(ansi256Color.toString()).isEqualTo("48;5;208");
+ }
+
+ @Test
+ void testIllegalColorCode() {
+ try {
+ new Ansi256Color.Foreground(256);
+ failBecauseExceptionWasNotThrown(IllegalArgumentException.class);
+ }
+ catch (IllegalArgumentException ex) {
+ assertThat(ex.getMessage()).isEqualTo("'colorCode' must be between 0 and 255.");
+ }
+ }
+
+}
diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/ansi/Ansi256PropertySourceTest.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/ansi/Ansi256PropertySourceTest.java
new file mode 100644
index 0000000000..5fcad0d36f
--- /dev/null
+++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/ansi/Ansi256PropertySourceTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2012-2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.boot.ansi;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Tests for {@link Ansi256PropertySource}.
+ *
+ * @author Toshiaki Maki
+ */
+class Ansi256PropertySourceTest {
+
+ private Ansi256PropertySource source = new Ansi256PropertySource("ansi256");
+
+ @AfterEach
+ void reset() {
+ AnsiOutput.setEnabled(AnsiOutput.Enabled.DETECT);
+ }
+
+ @Test
+ void getPropertyShouldConvertAnsi256ColorForeground() {
+ AnsiOutput.setEnabled(AnsiOutput.Enabled.ALWAYS);
+ final Object property = this.source.getProperty("Ansi256Color.Foreground_100");
+ assertThat(property).isEqualTo("\033[38;5;100m");
+ }
+
+ @Test
+ void getPropertyShouldConvertAnsi256ColorBackground() {
+ AnsiOutput.setEnabled(AnsiOutput.Enabled.ALWAYS);
+ final Object property = this.source.getProperty("Ansi256Color.Background_100");
+ assertThat(property).isEqualTo("\033[48;5;100m");
+ }
+
+ @Test
+ void getMissingPropertyShouldReturnNull() {
+ AnsiOutput.setEnabled(AnsiOutput.Enabled.ALWAYS);
+ final Object property = this.source.getProperty("Ansi256Color.ForeGround_100");
+ assertThat(property).isNull();
+ }
+
+}