From 6718b10fa9298e7cd187b526c75fdbd9df6483f3 Mon Sep 17 00:00:00 2001 From: dugenkui Date: Tue, 29 Mar 2022 12:59:54 +0800 Subject: [PATCH] Order ExitCodeGenerators and return first non-zero exit code See gh-30457 --- .../asciidoc/features/spring-application.adoc | 3 ++- .../boot/ExitCodeGenerators.java | 14 ++++++++++++-- .../boot/ExitCodeGeneratorsTests.java | 19 +++++++++++++++++++ 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/spring-application.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/spring-application.adoc index 52f7c34750..fa2546775e 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/spring-application.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/spring-application.adoc @@ -354,7 +354,8 @@ include::code:MyApplication[] Also, the `ExitCodeGenerator` interface may be implemented by exceptions. When such an exception is encountered, Spring Boot returns the exit code provided by the implemented `getExitCode()` method. - +If several `ExitCodeGenerator` are registered in a `ExitCodeGenerators`, they can be called in a specific order by using `org.springframework.core.annotation.Order` annotation or by implementing `org.springframework.core.Ordered`, +and `ExitCodeGenerators#getExitCode()` will return the first non-zero value. [[features.spring-application.admin]] === Admin Features diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/ExitCodeGenerators.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/ExitCodeGenerators.java index f26f16ea16..5fdbe92c66 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/ExitCodeGenerators.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/ExitCodeGenerators.java @@ -21,14 +21,22 @@ import java.util.Arrays; import java.util.Iterator; import java.util.List; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.AnnotationAwareOrderComparator; +import org.springframework.core.annotation.Order; import org.springframework.util.Assert; /** * Maintains a collection of {@link ExitCodeGenerator} instances and allows the final exit * code to be calculated. * + *

If several {@code ExitCodeGenerator} are registered in {@code ExitCodeGenerators}, + * they can be called in a specific order by using {@link Order @Order} or by implementing {@link Ordered}, + * and {@link #getExitCode()} will return the first non-zero value. + * * @author Dave Syer * @author Phillip Webb + * @author GenKui Du * @see #getExitCode() * @see ExitCodeGenerator */ @@ -84,15 +92,17 @@ class ExitCodeGenerators implements Iterable { */ int getExitCode() { int exitCode = 0; + AnnotationAwareOrderComparator.sort(this.generators); for (ExitCodeGenerator generator : this.generators) { try { int value = generator.getExitCode(); - if (value > 0 && value > exitCode || value < 0 && value < exitCode) { + if (value != 0) { exitCode = value; + break; } } catch (Exception ex) { - exitCode = (exitCode != 0) ? exitCode : 1; + exitCode = 1; ex.printStackTrace(); } } diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/ExitCodeGeneratorsTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/ExitCodeGeneratorsTests.java index 9a81e71626..e6252fa757 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/ExitCodeGeneratorsTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/ExitCodeGeneratorsTests.java @@ -20,11 +20,13 @@ import java.io.IOException; import java.util.List; import org.junit.jupiter.api.Test; +import org.springframework.core.Ordered; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.withSettings; /** * Tests for {@link ExitCodeGenerators}. @@ -89,12 +91,29 @@ class ExitCodeGeneratorsTests { assertThat(generators.getExitCode()).isEqualTo(2); } + @Test + void getExitCodeWithOrderedGenerator() { + ExitCodeGenerators generators = new ExitCodeGenerators(); + generators.add(mockGenerator(0, 1)); + generators.add(mockGenerator(1, 3)); + generators.add(mockGenerator(2, 2)); + generators.add(mockGenerator(3, 4)); + assertThat(generators.getExitCode()).isEqualTo(2); + } + private ExitCodeGenerator mockGenerator(int exitCode) { ExitCodeGenerator generator = mock(ExitCodeGenerator.class); given(generator.getExitCode()).willReturn(exitCode); return generator; } + private ExitCodeGenerator mockGenerator(int exitCode, int orderValue) { + ExitCodeGenerator generator = mock(ExitCodeGenerator.class, withSettings().extraInterfaces(Ordered.class)); + given(generator.getExitCode()).willReturn(exitCode); + given(((Ordered) generator).getOrder()).willReturn(orderValue); + return generator; + } + private ExitCodeExceptionMapper mockMapper(Class exceptionType, int exitCode) { return (exception) -> { if (exceptionType.isInstance(exception)) {