Merge branch '2.7.x'

pull/30580/head
Andy Wilkinson 3 years ago
commit e6b485b317

@ -352,6 +352,9 @@ include::code:MyApplication[]
Also, the `ExitCodeGenerator` interface may be implemented by exceptions. 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. When such an exception is encountered, Spring Boot returns the exit code provided by the implemented `getExitCode()` method.
If there is more than `ExitCodeGenerator`, the first non-zero exit code that is generated is used.
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.
[[features.spring-application.admin]] [[features.spring-application.admin]]

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -21,14 +21,19 @@ import java.util.Arrays;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; 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; import org.springframework.util.Assert;
/** /**
* Maintains a collection of {@link ExitCodeGenerator} instances and allows the final exit * Maintains an ordered collection of {@link ExitCodeGenerator} instances and allows the
* code to be calculated. * final exit code to be calculated. Generators are ordered by {@link Order @Order} and
* {@link Ordered}.
* *
* @author Dave Syer * @author Dave Syer
* @author Phillip Webb * @author Phillip Webb
* @author GenKui Du
* @see #getExitCode() * @see #getExitCode()
* @see ExitCodeGenerator * @see ExitCodeGenerator
*/ */
@ -71,6 +76,7 @@ class ExitCodeGenerators implements Iterable<ExitCodeGenerator> {
void add(ExitCodeGenerator generator) { void add(ExitCodeGenerator generator) {
Assert.notNull(generator, "Generator must not be null"); Assert.notNull(generator, "Generator must not be null");
this.generators.add(generator); this.generators.add(generator);
AnnotationAwareOrderComparator.sort(this.generators);
} }
@Override @Override
@ -79,7 +85,8 @@ class ExitCodeGenerators implements Iterable<ExitCodeGenerator> {
} }
/** /**
* Get the final exit code that should be returned based on all contained generators. * Get the final exit code that should be returned. The final exit code is the first
* non-zero exit code that is {@link ExitCodeGenerator#getExitCode generated}.
* @return the final exit code. * @return the final exit code.
*/ */
int getExitCode() { int getExitCode() {
@ -87,12 +94,13 @@ class ExitCodeGenerators implements Iterable<ExitCodeGenerator> {
for (ExitCodeGenerator generator : this.generators) { for (ExitCodeGenerator generator : this.generators) {
try { try {
int value = generator.getExitCode(); int value = generator.getExitCode();
if (value > 0 && value > exitCode || value < 0 && value < exitCode) { if (value != 0) {
exitCode = value; exitCode = value;
break;
} }
} }
catch (Exception ex) { catch (Exception ex) {
exitCode = (exitCode != 0) ? exitCode : 1; exitCode = 1;
ex.printStackTrace(); ex.printStackTrace();
} }
} }

@ -61,7 +61,9 @@ import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericApplicationContext; import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.GenericTypeResolver; import org.springframework.core.GenericTypeResolver;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.CommandLinePropertySource; import org.springframework.core.env.CommandLinePropertySource;
import org.springframework.core.env.CompositePropertySource; import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.ConfigurableEnvironment;
@ -1320,9 +1322,10 @@ public class SpringApplication {
* Static helper that can be used to exit a {@link SpringApplication} and obtain a * Static helper that can be used to exit a {@link SpringApplication} and obtain a
* code indicating success (0) or otherwise. Does not throw exceptions but should * code indicating success (0) or otherwise. Does not throw exceptions but should
* print stack traces of any encountered. Applies the specified * print stack traces of any encountered. Applies the specified
* {@link ExitCodeGenerator} in addition to any Spring beans that implement * {@link ExitCodeGenerator ExitCodeGenerators} in addition to any Spring beans that
* {@link ExitCodeGenerator}. In the case of multiple exit codes the highest value * implement {@link ExitCodeGenerator}. When multiple generators are available, the
* will be used (or if all values are negative, the lowest value will be used) * first non-zero exit code is used. Generators ordered based on their {@link Ordered}
* implementation and {@link Order @Order} annotation.
* @param context the context to close if possible * @param context the context to close if possible
* @param exitCodeGenerators exit code generators * @param exitCodeGenerators exit code generators
* @return the outcome (0 if successful) * @return the outcome (0 if successful)

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -21,10 +21,13 @@ import java.util.List;
import org.junit.jupiter.api.Test; 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.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.withSettings;
/** /**
* Tests for {@link ExitCodeGenerators}. * Tests for {@link ExitCodeGenerators}.
@ -62,18 +65,9 @@ class ExitCodeGeneratorsTests {
} }
@Test @Test
void getExitCodeWhenAllNegativeShouldReturnLowestValue() { void getExitCodeWithUnorderedGeneratorsReturnsFirstNonZeroExitCode() {
ExitCodeGenerators generators = new ExitCodeGenerators();
generators.add(mockGenerator(-1));
generators.add(mockGenerator(-3));
generators.add(mockGenerator(-2));
assertThat(generators.getExitCode()).isEqualTo(-3);
}
@Test
void getExitCodeWhenAllPositiveShouldReturnHighestValue() {
ExitCodeGenerators generators = new ExitCodeGenerators(); ExitCodeGenerators generators = new ExitCodeGenerators();
generators.add(mockGenerator(1)); generators.add(mockGenerator(0));
generators.add(mockGenerator(3)); generators.add(mockGenerator(3));
generators.add(mockGenerator(2)); generators.add(mockGenerator(2));
assertThat(generators.getExitCode()).isEqualTo(3); assertThat(generators.getExitCode()).isEqualTo(3);
@ -89,12 +83,29 @@ class ExitCodeGeneratorsTests {
assertThat(generators.getExitCode()).isEqualTo(2); assertThat(generators.getExitCode()).isEqualTo(2);
} }
@Test
void getExitCodeWithOrderedGeneratorsReturnsFirstNonZeroExitCode() {
ExitCodeGenerators generators = new ExitCodeGenerators();
generators.add(orderedMockGenerator(0, 1));
generators.add(orderedMockGenerator(1, 3));
generators.add(orderedMockGenerator(2, 2));
generators.add(mockGenerator(3));
assertThat(generators.getExitCode()).isEqualTo(2);
}
private ExitCodeGenerator mockGenerator(int exitCode) { private ExitCodeGenerator mockGenerator(int exitCode) {
ExitCodeGenerator generator = mock(ExitCodeGenerator.class); ExitCodeGenerator generator = mock(ExitCodeGenerator.class);
given(generator.getExitCode()).willReturn(exitCode); given(generator.getExitCode()).willReturn(exitCode);
return generator; return generator;
} }
private ExitCodeGenerator orderedMockGenerator(int exitCode, int order) {
ExitCodeGenerator generator = mock(ExitCodeGenerator.class, withSettings().extraInterfaces(Ordered.class));
given(generator.getExitCode()).willReturn(exitCode);
given(((Ordered) generator).getOrder()).willReturn(order);
return generator;
}
private ExitCodeExceptionMapper mockMapper(Class<?> exceptionType, int exitCode) { private ExitCodeExceptionMapper mockMapper(Class<?> exceptionType, int exitCode) {
return (exception) -> { return (exception) -> {
if (exceptionType.isInstance(exception)) { if (exceptionType.isInstance(exception)) {

Loading…
Cancel
Save