Skip to content

OpenAPIService is using ObjectMapper without configured modules since SpringDoc 1.6.7 #1655

Closed
@mdjimy

Description

@mdjimy

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions