Reputation: 30985
I want to have a standard custom exception thrown from the controller advice aspect but for some reason my custom exception is not being caught by spring boot (1.3.3-RELEASE).
This is the code I have:
My Test
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(MyApplication.class)
@WebIntegrationTest("server.port:9000")
public class ControllerTest {
private final String URL = "http://localhost:9000";
@Test
public void testCustomExceptionResponse() {
// Invoke my controller generating some exception
Map error = restTemplate.getForObject(URL+"/exception/", Map.class);
assertTrue(error.get("exception").contains("MyCustomException"));
}
}
The controller
@RequestMapping(value = "/", method = RequestMethod.GET)
public List<Object> findAll() throws Exception {
// generate whatever exception here
if (1<2) throw new IllegalIdentifierException("test whatever exception");
return ccRepository.findByActive(true);
}
The GlobalExceptionHandler annotated with @ControllerAdvice
@ControllerAdvice
public class GlobalExceptionHandler {
private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
// Catch whatever exception to throw my custom exception
@ExceptionHandler(Exception.class)
public void handleException(Exception ex) throws Exception {
logger.error("Exception Occured: ", ex);
throw new MyCustomException(ex.getLocalizedMessage());
}
}
I have debugged the code and the handleException method is being executed, however the weird thing is that MyCustomException is being thrown but the controller response is returning the original exception thrown:
{timestamp=1473963128439, status=500, error=Internal Server Error, exception=org.hibernate.metamodel.relational.IllegalIdentifierException, message=test whatever exception, path=/exception/}
I'm expecting to have something like this:
exception=com.myapp.MyCustomException
As far as I know, the controller advice is the generic way to catch all the exceptions in the controllers to have some logic tied (which in my case is the logger) and then I customized the unexpected exceptions by using a custom one.
Am I missing anything about how Spring Boot handles the exceptions?
Upvotes: 5
Views: 5319
Reputation: 17025
That's not exactly the purpose of ControllerAdvice.
The Controller Advice is meant to return a valid Http response in case of an error.
For instance, you could change it to:
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleException(Exception ex) throws Exception {
System.out.println("Exception Occured: " + ex);
return ResponseEntity
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("Exception: " + ex.getLocalizedMessage());
}
}
Thus:
You can test it with MockMvc
:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(Launcher.class)
@WebAppConfiguration
public class ControllerTest {
@Autowired
private WebApplicationContext webApplicationContext;
@Test
public void testCustomExceptionResponse() throws Exception {
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
mockMvc.perform(MockMvcRequestBuilders.get("/your/uri"))
.andExpect(MockMvcResultMatchers.status().isInternalServerError())
.andExpect(MockMvcResultMatchers.content().string("Exception: test whatever exception"));
assertTrue(true);
}
}
Upvotes: 3
Reputation: 835
I've just created a sample project based on your code, try to change this line:
Map error = restTemplate.getForObject("/exception/", Map.class);
to
Map error = restTemplate.getForObject("http://localhost:9000/", Map.class);
since your RequestMapping
is looking for /
I think some other method is handling your http request, that explains the hibernate error message as well, since 1<2
return true all the time.
My logs look like this:
2016-09-15 22:21:32.101 ERROR 7688 --- [nio-9000-exec-1] tonakai.GlobalExceptionHandler : Exception Occured:
tonakai.IllegalIdentifierException: test whatever exception
at tonakai.SampleController.findAll(SampleController.java:19) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_102]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_102]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_102]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_102]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221) ~[spring-web-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136) ~[spring-web-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110) ~[spring-webmvc-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:817) ~[spring-webmvc-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:731) ~[spring-webmvc-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) ~[spring-webmvc-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at org.springframework.web.servlet.DispatcherServlet
Upvotes: 0