Skip to content

Commit 8727361

Browse files
committed
Polish "Order ExitCodeGenerators and return first non-zero exit code"
See gh-30457
1 parent 6718b10 commit 8727361

File tree

4 files changed

+28
-33
lines changed

4 files changed

+28
-33
lines changed

spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/spring-application.adoc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -354,8 +354,10 @@ include::code:MyApplication[]
354354
Also, the `ExitCodeGenerator` interface may be implemented by exceptions.
355355
When such an exception is encountered, Spring Boot returns the exit code provided by the implemented `getExitCode()` method.
356356

357-
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`,
358-
and `ExitCodeGenerators#getExitCode()` will return the first non-zero value.
357+
If there is more than `ExitCodeGenerator`, the first non-zero exit code that is generated is used.
358+
To control the order in which the generators are called, additionally implement the `org.springframework.core.Ordered` interface or use the `org.springframework.core.annotation.Order` annotation.
359+
360+
359361

360362
[[features.spring-application.admin]]
361363
=== Admin Features

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/ExitCodeGenerators.java

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2019 the original author or authors.
2+
* Copyright 2012-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -27,12 +27,9 @@
2727
import org.springframework.util.Assert;
2828

2929
/**
30-
* Maintains a collection of {@link ExitCodeGenerator} instances and allows the final exit
31-
* code to be calculated.
32-
*
33-
* <p>If several {@code ExitCodeGenerator} are registered in {@code ExitCodeGenerators},
34-
* they can be called in a specific order by using {@link Order @Order} or by implementing {@link Ordered},
35-
* and {@link #getExitCode()} will return the first non-zero value.
30+
* Maintains an ordered collection of {@link ExitCodeGenerator} instances and allows the
31+
* final exit code to be calculated. Generators are ordered by {@link Order @Order} and
32+
* {@link Ordered}.
3633
*
3734
* @author Dave Syer
3835
* @author Phillip Webb
@@ -79,6 +76,7 @@ void addAll(Iterable<? extends ExitCodeGenerator> generators) {
7976
void add(ExitCodeGenerator generator) {
8077
Assert.notNull(generator, "Generator must not be null");
8178
this.generators.add(generator);
79+
AnnotationAwareOrderComparator.sort(this.generators);
8280
}
8381

8482
@Override
@@ -87,12 +85,12 @@ public Iterator<ExitCodeGenerator> iterator() {
8785
}
8886

8987
/**
90-
* Get the final exit code that should be returned based on all contained generators.
88+
* Get the final exit code that should be returned. The final exit code is the first
89+
* non-zero exit code that is {@link ExitCodeGenerator#getExitCode generated}.
9190
* @return the final exit code.
9291
*/
9392
int getExitCode() {
9493
int exitCode = 0;
95-
AnnotationAwareOrderComparator.sort(this.generators);
9694
for (ExitCodeGenerator generator : this.generators) {
9795
try {
9896
int value = generator.getExitCode();

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,9 @@
6161
import org.springframework.context.support.AbstractApplicationContext;
6262
import org.springframework.context.support.GenericApplicationContext;
6363
import org.springframework.core.GenericTypeResolver;
64+
import org.springframework.core.Ordered;
6465
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
66+
import org.springframework.core.annotation.Order;
6567
import org.springframework.core.env.CommandLinePropertySource;
6668
import org.springframework.core.env.CompositePropertySource;
6769
import org.springframework.core.env.ConfigurableEnvironment;
@@ -1320,9 +1322,10 @@ public static void main(String[] args) throws Exception {
13201322
* Static helper that can be used to exit a {@link SpringApplication} and obtain a
13211323
* code indicating success (0) or otherwise. Does not throw exceptions but should
13221324
* print stack traces of any encountered. Applies the specified
1323-
* {@link ExitCodeGenerator} in addition to any Spring beans that implement
1324-
* {@link ExitCodeGenerator}. In the case of multiple exit codes the highest value
1325-
* will be used (or if all values are negative, the lowest value will be used)
1325+
* {@link ExitCodeGenerator ExitCodeGenerators} in addition to any Spring beans that
1326+
* implement {@link ExitCodeGenerator}. When multiple generators are available, the
1327+
* first non-zero exit code is used. Generators ordered based on their {@link Ordered}
1328+
* implementation and {@link Order @Order} annotation.
13261329
* @param context the context to close if possible
13271330
* @param exitCodeGenerators exit code generators
13281331
* @return the outcome (0 if successful)

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/ExitCodeGeneratorsTests.java

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2019 the original author or authors.
2+
* Copyright 2012-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@
2020
import java.util.List;
2121

2222
import org.junit.jupiter.api.Test;
23+
2324
import org.springframework.core.Ordered;
2425

2526
import static org.assertj.core.api.Assertions.assertThat;
@@ -64,18 +65,9 @@ void getExitCodeWhenGeneratorThrowsShouldReturnOne() {
6465
}
6566

6667
@Test
67-
void getExitCodeWhenAllNegativeShouldReturnLowestValue() {
68-
ExitCodeGenerators generators = new ExitCodeGenerators();
69-
generators.add(mockGenerator(-1));
70-
generators.add(mockGenerator(-3));
71-
generators.add(mockGenerator(-2));
72-
assertThat(generators.getExitCode()).isEqualTo(-3);
73-
}
74-
75-
@Test
76-
void getExitCodeWhenAllPositiveShouldReturnHighestValue() {
68+
void getExitCodeWithUnorderedGeneratorsReturnsFirstNonZeroExitCode() {
7769
ExitCodeGenerators generators = new ExitCodeGenerators();
78-
generators.add(mockGenerator(1));
70+
generators.add(mockGenerator(0));
7971
generators.add(mockGenerator(3));
8072
generators.add(mockGenerator(2));
8173
assertThat(generators.getExitCode()).isEqualTo(3);
@@ -92,12 +84,12 @@ void getExitCodeWhenUsingExitCodeExceptionMapperShouldCallMapper() {
9284
}
9385

9486
@Test
95-
void getExitCodeWithOrderedGenerator() {
87+
void getExitCodeWithOrderedGeneratorsReturnsFirstNonZeroExitCode() {
9688
ExitCodeGenerators generators = new ExitCodeGenerators();
97-
generators.add(mockGenerator(0, 1));
98-
generators.add(mockGenerator(1, 3));
99-
generators.add(mockGenerator(2, 2));
100-
generators.add(mockGenerator(3, 4));
89+
generators.add(orderedMockGenerator(0, 1));
90+
generators.add(orderedMockGenerator(1, 3));
91+
generators.add(orderedMockGenerator(2, 2));
92+
generators.add(mockGenerator(3));
10193
assertThat(generators.getExitCode()).isEqualTo(2);
10294
}
10395

@@ -107,10 +99,10 @@ private ExitCodeGenerator mockGenerator(int exitCode) {
10799
return generator;
108100
}
109101

110-
private ExitCodeGenerator mockGenerator(int exitCode, int orderValue) {
102+
private ExitCodeGenerator orderedMockGenerator(int exitCode, int order) {
111103
ExitCodeGenerator generator = mock(ExitCodeGenerator.class, withSettings().extraInterfaces(Ordered.class));
112104
given(generator.getExitCode()).willReturn(exitCode);
113-
given(((Ordered) generator).getOrder()).willReturn(orderValue);
105+
given(((Ordered) generator).getOrder()).willReturn(order);
114106
return generator;
115107
}
116108

0 commit comments

Comments
 (0)