For those working with Spring Boot REST API, there should be already countless occasions that you have encountered errors like this:
{
"timestamp": "2022-01-19T14:36:29.443+00:00",
"status": 500,
"error": "Internal Server Error",
"exception": "java.lang.RuntimeException",
"trace": "java.lang.RuntimeException: die!\n\tat net.ketone.error.ErrorApi.die(ErrorApi.java:14)...",
"message": "die!",
"path": "/api"
}
Have you ever thought of deserializing this return JSON and wondering whether Spring actually has a Class mapped to it? Surprisingly, from what I've researched in Google, it seemed that there actually isn't one equivalent Class in the Spring Boot package that would map to this JSON; it is rather the result of a dynamic composition from selected fields in DefaultErrorAttributes.
Error Field Configuration
Before deserializing the JSON, it is worth pointing out that a few of these fields are disabled by default -- in particular when they changed hide the "message" field by default in 2.3.0 it caused a lot of questions to pop up in StackOverflow. You could find all the error-related configurations here and the official list of all server configurations here. For our purposes, let's just enable everything in application.yml:
server:
error:
include-message: always
include-stacktrace: always
include-binding-errors: always
include-exception: true
Deserialization
The following is from the official list of DefaultErrorAttributes when this post was written:
Default implementation of ErrorAttributes. Provides the following attributes when possible:
- timestamp - The time that the errors were extracted
- status - The status code
- error - The error reason
- exception - The class name of the root exception (if configured)
- message - The exception message (if configured)
- errors - Any ObjectErrors from a BindingResult exception (if configured)
- trace - The exception stack trace (if configured)
- path - The URL path when the exception was raised
I've made this class with the above fields mapped to a meaningful POJO so that they could be consumed by another web service. Feel free to copy and reuse the code below:
You will need the following maven dependencies to deserialize it:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.13.0</version>
</dependency>
Then the deserialization code (checked Exception not caught here):
DefaultErrorAttributesPojo ea = new ObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.registerModule(new JavaTimeModule())
.readValue(ex.getResponseBodyAsString(), DefaultErrorAttributesPojo.class);
You could find the full example in this repo. Till next time, happy coding!
Comments (0)