Description
Bug description
Originally in OpenAPIService.build(Locale locale)
ObjectMapper
was obtained via Json.mapper()
.
This behaviour was changed in SpringDoc 1.6.7 in order to resolve #1525 to new ObjectMapper()
. The problem is that this way obtained instance of ObjectMapper
has no longer registered JavaTimeModule
, Swagger v3 DeserializationModule
and mixins.
In my application I have OperationCustomizer
that adds to all REST operations schema for 5xx responses that are produced by @ControllerAdvice
. In 5xx response schema I'm using Instant
and since JavaTimeModule
is absent, attempt to serialize openAPI
to JSON and deserialize it produces JsonProcessingException
. This exception is then logged with WARN
level and suppressed resulting in calculatedOpenAPI = null
which then later in execution is causing NullPointerException
(see output log below)
INFO test.TestController : Starting TestController using Java 17.0.1 on ...
INFO test.TestController : No active profile set, falling back to 1 default profile: "default"
INFO o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
INFO o.apache.catalina.core.StandardService : Starting service [Tomcat]
INFO org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.62]
INFO o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
INFO w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 622 ms
INFO o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
INFO test.TestController : Started TestController in 1.387 seconds (JVM running for 1.657)
INFO o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
INFO o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
INFO o.s.web.servlet.DispatcherServlet : Completed initialization in 1 ms
WARN org.springdoc.core.OpenAPIService : Json Processing Exception occurred: Java 8 date/time type `java.time.OffsetDateTime` not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling (through reference chain: io.swagger.v3.oas.models.OpenAPI["components"]->io.swagger.v3.oas.models.Components["schemas"]->java.util.LinkedHashMap["ErrorResponse"]->io.swagger.v3.oas.models.media.Schema["properties"]->java.util.LinkedHashMap["timestamp"]->io.swagger.v3.oas.models.media.DateTimeSchema["example"])
ERROR o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException: Cannot invoke "io.swagger.v3.oas.models.OpenAPI.getInfo()" because "this.calculatedOpenAPI" is null] with root cause
java.lang.NullPointerException: Cannot invoke "io.swagger.v3.oas.models.OpenAPI.getInfo()" because "this.calculatedOpenAPI" is null
at org.springdoc.core.OpenAPIService.build(OpenAPIService.java:262) ~[springdoc-openapi-common-1.6.8.jar:1.6.8]
at org.springdoc.api.AbstractOpenApiResource.getOpenApi(AbstractOpenApiResource.java:308) ~[springdoc-openapi-common-1.6.8.jar:1.6.8]
at org.springdoc.webmvc.api.OpenApiResource.openapiJson(OpenApiResource.java:132) ~[springdoc-openapi-webmvc-core-1.6.8.jar:1.6.8]
at org.springdoc.webmvc.api.OpenApiWebMvcResource.openapiJson(OpenApiWebMvcResource.java:111) ~[springdoc-openapi-webmvc-core-1.6.8.jar:1.6.8]
...
Sample code to Reproduce
@RestController
@SpringBootApplication
public class TestController {
public static void main(String[] args) { SpringApplication.run(TestController.class, args); }
@GetMapping("/test")
public void test() {}
@Bean
public OpenAPI openAPI() { return new OpenAPI().components(new Components()); }
@Bean
public OperationCustomizer operationCustomizer(OpenAPI api) {
var errorResponseSchema = SpringDocAnnotationsUtils.extractSchema(
api.getComponents(),
ErrorResponse.class,
null,
null
);
var errorApiResponse = new ApiResponse().content(new Content().addMediaType(
APPLICATION_JSON_VALUE,
new MediaType().schema(errorResponseSchema)
));
return (Operation operation, HandlerMethod handlerMethod) -> {
operation.getResponses().addApiResponse("5xx", errorApiResponse);
return operation;
};
}
public record ErrorResponse(
@Schema(example = "2022-05-09T00:00:00.000Z") Instant timestamp,
@Schema(example = "{\"param1\":\"val1\",\"param2\":\"val2\"}") Map<String, Object> data
) {}
}
Code snippet abowe works for SpringDoc 1.6.6 or older. Since SpringDoc 1.6.7 /v3/api-docs
endpoint fails with HTTP 500 response due to problem described above.