Skip to content

Commit 2e114b6

Browse files
committed
Merge branch '3.1.x' into 3.2.x
Closes gh-40450
2 parents f78b239 + 172b3d5 commit 2e114b6

File tree

2 files changed

+59
-1
lines changed

2 files changed

+59
-1
lines changed

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

+11-1
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
import org.springframework.context.support.AbstractApplicationContext;
8181
import org.springframework.context.support.GenericApplicationContext;
8282
import org.springframework.core.GenericTypeResolver;
83+
import org.springframework.core.NativeDetector;
8384
import org.springframework.core.OrderComparator;
8485
import org.springframework.core.OrderComparator.OrderSourceProvider;
8586
import org.springframework.core.Ordered;
@@ -848,7 +849,16 @@ private void reportFailure(Collection<SpringBootExceptionReporter> exceptionRepo
848849
// Continue with normal handling of the original failure
849850
}
850851
if (logger.isErrorEnabled()) {
851-
logger.error("Application run failed", failure);
852+
if (NativeDetector.inNativeImage()) {
853+
// Depending on how early the failure was, logging may not work in a
854+
// native image so we output the stack trace directly to System.out
855+
// instead.
856+
System.out.println("Application run failed");
857+
failure.printStackTrace(System.out);
858+
}
859+
else {
860+
logger.error("Application run failed", failure);
861+
}
852862
registerLoggedException(failure);
853863
}
854864
}

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

+48
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
import org.springframework.boot.context.event.ApplicationStartingEvent;
7474
import org.springframework.boot.context.event.SpringApplicationEvent;
7575
import org.springframework.boot.convert.ApplicationConversionService;
76+
import org.springframework.boot.testsupport.classpath.ForkedClassPath;
7677
import org.springframework.boot.testsupport.system.CapturedOutput;
7778
import org.springframework.boot.testsupport.system.OutputCaptureExtension;
7879
import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
@@ -753,6 +754,53 @@ void failureInReadyEventListenerCloseApplicationContext(CapturedOutput output) {
753754
assertThat(output).contains("Application run failed");
754755
}
755756

757+
@Test
758+
void failureOnTheJvmLogsApplicationRunFailed(CapturedOutput output) {
759+
SpringApplication application = new SpringApplication(ExampleConfig.class);
760+
application.setWebApplicationType(WebApplicationType.NONE);
761+
ExitCodeListener exitCodeListener = new ExitCodeListener();
762+
application.addListeners(exitCodeListener);
763+
@SuppressWarnings("unchecked")
764+
ApplicationListener<SpringApplicationEvent> listener = mock(ApplicationListener.class);
765+
application.addListeners(listener);
766+
ExitStatusException failure = new ExitStatusException();
767+
willThrow(failure).given(listener).onApplicationEvent(isA(ApplicationReadyEvent.class));
768+
assertThatExceptionOfType(RuntimeException.class).isThrownBy(application::run);
769+
then(listener).should().onApplicationEvent(isA(ApplicationReadyEvent.class));
770+
then(listener).should(never()).onApplicationEvent(isA(ApplicationFailedEvent.class));
771+
assertThat(exitCodeListener.getExitCode()).isEqualTo(11);
772+
// Leading space only happens when logging
773+
assertThat(output).contains(" Application run failed").contains("ExitStatusException");
774+
}
775+
776+
@Test
777+
@ForkedClassPath
778+
void failureInANativeImageWritesFailureToSystemOut(CapturedOutput output) {
779+
System.setProperty("org.graalvm.nativeimage.imagecode", "true");
780+
try {
781+
SpringApplication application = new SpringApplication(ExampleConfig.class);
782+
application.setWebApplicationType(WebApplicationType.NONE);
783+
ExitCodeListener exitCodeListener = new ExitCodeListener();
784+
application.addListeners(exitCodeListener);
785+
@SuppressWarnings("unchecked")
786+
ApplicationListener<SpringApplicationEvent> listener = mock(ApplicationListener.class);
787+
application.addListeners(listener);
788+
ExitStatusException failure = new ExitStatusException();
789+
willThrow(failure).given(listener).onApplicationEvent(isA(ApplicationReadyEvent.class));
790+
assertThatExceptionOfType(RuntimeException.class).isThrownBy(application::run);
791+
then(listener).should().onApplicationEvent(isA(ApplicationReadyEvent.class));
792+
then(listener).should(never()).onApplicationEvent(isA(ApplicationFailedEvent.class));
793+
assertThat(exitCodeListener.getExitCode()).isEqualTo(11);
794+
// Leading space only happens when logging
795+
assertThat(output).doesNotContain(" Application run failed")
796+
.contains("Application run failed")
797+
.contains("ExitStatusException");
798+
}
799+
finally {
800+
System.clearProperty("org.graalvm.nativeimage.imagecode");
801+
}
802+
}
803+
756804
@Test
757805
void loadSources() {
758806
Class<?>[] sources = { ExampleConfig.class, TestCommandLineRunner.class };

0 commit comments

Comments
 (0)