From 03669002de17b5fe731253e3b7cc51e9e87356f3 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 21 Jan 2016 10:21:07 +0000 Subject: [PATCH] Check for null context when trying to find an exception mapper If application context refresh fails, SpringApplication will have a null context. Previously, this would result in an NPE when looking for an ExitCodeExceptionMapper. This commit updates SpringApplication to gracefully handle the context being null when looking for an ExitCodeExceptionMapper. Closes gh-4803 --- .../boot/SpringApplication.java | 3 ++ .../boot/SpringApplicationTests.java | 42 +++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java b/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java index d18f59373a..44dd897e9b 100644 --- a/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java +++ b/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java @@ -881,6 +881,9 @@ public class SpringApplication { private int getExitCodeFromMappedException(ConfigurableApplicationContext context, Throwable exception) { + if (context == null) { + return 0; + } ExitCodeGenerators generators = new ExitCodeGenerators(); Collection beans = context .getBeansOfType(ExitCodeExceptionMapper.class).values(); diff --git a/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java b/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java index 3593019144..dec42064e9 100644 --- a/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java @@ -24,6 +24,8 @@ import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; +import javax.annotation.PostConstruct; + import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -74,6 +76,7 @@ import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.isA; +import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.sameInstance; import static org.hamcrest.Matchers.startsWith; import static org.junit.Assert.assertArrayEquals; @@ -83,6 +86,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyObject; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.mock; @@ -615,6 +619,31 @@ public class SpringApplicationTests { assertThat(listener.getExitCode(), equalTo(11)); } + @Test + public void exceptionFromRefreshIsHandledGracefully() throws Exception { + final SpringBootExceptionHandler handler = mock(SpringBootExceptionHandler.class); + SpringApplication application = new SpringApplication( + RefreshFailureConfig.class) { + + @Override + SpringBootExceptionHandler getSpringBootExceptionHandler() { + return handler; + } + + }; + ExitCodeListener listener = new ExitCodeListener(); + application.addListeners(listener); + application.setWebEnvironment(false); + try { + application.run(); + fail("Did not throw"); + } + catch (RuntimeException ex) { + } + verify(handler).registerLoggedException(any(RefreshFailureException.class)); + assertThat(this.output.toString(), not(containsString("NullPointerException"))); + } + @Test public void defaultCommandLineArgs() throws Exception { SpringApplication application = new SpringApplication(ExampleConfig.class); @@ -966,6 +995,15 @@ public class SpringApplicationTests { } + @Configuration + static class RefreshFailureConfig { + + @PostConstruct + public void fail() { + throw new RefreshFailureException(); + } + } + static class ExitStatusException extends RuntimeException implements ExitCodeGenerator { @@ -976,6 +1014,10 @@ public class SpringApplicationTests { } + static class RefreshFailureException extends RuntimeException { + + } + static class AbstractTestRunner implements ApplicationContextAware, Ordered { private final String[] expectedBefore;