0

Scenario:

There is a method in a API response object which concatenates two fields. Say getFullName() which returns name in the format "lastname, firstname". This object is returned like below from the REST controller endpoint method.

    @PostMapping(consumes = {"application/json"}, produces = {"application/json"})
    public ResponseEntity<User> createUser(@RequestBody User payload) throws Exception {
        User data = userService.createUser(payload);
        return ResponseEntity.created(URI.create(data.getId())).body(data);
    }

Unfortunately if there is an exception in this method, for example a NPE, it is neither getting logged nor generating the response with exception message. Instead the spring is returning a 500 error with boiler plate "Internal Server Error" html (given below). It was very difficult to figure out the error line since there was no stacktrace being printed even while debugging.

enter image description here

On further research, I found that the exception is from com.fasterxml.jackson.databind.ser.std. BeanSerializerBase due to a NPE from the getter method (fixed the same). However, I am wondering why this is not getting logged or printing the stacktrace in debug console?

vinodpthmn
  • 1,062
  • 14
  • 28
  • The error may happened in when the spring solve data and bind it into args ```User payload``` . try to checkout the struct of ```User``` or there may be some potential global exception handler catch the error and do nothing before response? – Peng Jun 24 '23 at 14:13
  • 1
    Seems like there is a `@ControllerAdvice` catching all exceptions. Check out if your debug console has a row with text `resolved` – meridbt Jun 24 '23 at 17:08
  • 1
    Can you post your logging configuration as well ? Also I agree with @meridbt, there might be something wrong with your exception handling configuration. – Angela Lopez Jun 25 '23 at 12:33
  • @Peng, the issue is not the error. That was an NPE and I fixed the same. My concern is why spring missed to log this error, and nothing in debug console as well. – vinodpthmn Jun 25 '23 at 14:53
  • @vinodpthmn if you ensure that there is no global exception handler which potentially handle the error and no action before reponse ,. The best way is debug line by line , so that you would not miss or ignore some else which you have not noticed before . comparing with spring framework , our code snippet has more risk that occur the bug – Peng Jun 25 '23 at 16:03
  • @meridbt, you were right. The exception was getting logged as DEBUG (not as ERROR) with the message 'Resolved ----'. The custom controller advice which I wrote was not getting the exception rather the exception got handled by spring 'ExceptionHandlerExceptionResolver'. Thanks. – vinodpthmn Jun 25 '23 at 18:14
  • @AngelaLopez, your cue also helped me, the logging level was not set at DEBUG for org.springframework, my bad :( – vinodpthmn Jun 25 '23 at 18:17

1 Answers1

0

Here are my findings:

Enabling logging level as DEBUG for "org.springframework" started printing the DEBUG info starting with "Resolved xxxx". However, still not logging as ERROR, so exception stack trace was missing.

On further investigation I found, there is a condition in spring framework ExceptionHandlerExceptionResolver.doResolveHandlerMethodException() to print the exception stack trace only if the logging level is TRACE, I am wondering why though. Anyways, changing the logging level to TRACE started printing the exception stack trace.

However, I started pondering with the question why the exception didn't hit the custom ControllerAdvice? On a deep debugging, I got the answer. The exception handler resolver looks for matching @ExceptionHandler exception class mapping to invoke the appropriate handleException() method. In the context of this exception, the exception type 'HttpMessageNotWritable' was exclusively getting handled directly by ResponseEntityExceptionHandler.handleException() (base class).

Here, neither you can define another @ExceptionHandler mapping for HttpMessageNotWritable.class in the custom controller advice, nor you can override the handleException() method since it is defined as final in base class. A solution for this is explained in detail here Overriding the handling behavior for standard Spring MVC exceptions

vinodpthmn
  • 1,062
  • 14
  • 28