javaswaggerjerseyopenapiswagger-ui

How can I replace the generated OpenAPI spec in Swagger (JAX-RS + OpenApiResource) with a custom OpenAPI object?


I'm using Swagger with Jersey (JAX-RS) to serve API documentation. I configure Swagger like this:

ResourceConfig swaggerResourceConfig = new ResourceConfig()
    .packages("io.swagger.v3.jaxrs2.integration.resources")
    .register(OpenApiResource.class)
    .register(SwaggerSerializers.class)
    .register(AcceptHeaderOpenApiResource.class)
    .property("jersey.config.server.wadl.disableWadl", true);

SwaggerConfiguration oasConfig = new SwaggerConfiguration()
    .openApi(baseModel) // <-- I would want to serve the modified object, but can't at this point
    .prettyPrint(true)
    .resourcePackages(Set.of("my.api.package"));

OpenApiContext openApiCtx = new JaxrsOpenApiContextBuilder()
    .openApiConfiguration(oasConfig)
    .buildContext(true);

I have many endpoints where the ApiResponse.description is never set, so Swagger-UI shows errors: Structural error at {PATH} should have required property 'description' missingProperty: description. I wrote a helper function that traverses the generated OpenAPI model and fills in empty descriptions, which I tested out and it works:

public OpenAPI patchMissingDescriptions(OpenAPI openAPI) {
    if (openAPI.getPaths() != null) {
        for (Entry<String, PathItem> entry : openAPI.getPaths().entrySet()) {
            for (Operation operation : entry.getValue().readOperations()) {
                if (operation.getResponses() != null) {
                    for (Entry<String, ApiResponse> respEntry : operation.getResponses().entrySet()) {
                        ApiResponse response = respEntry.getValue();
                        if (response.getDescription() == null) {
                            response.setDescription("some description");
                        }
                    }
                }
            }
        }
    }
    return openAPI;
}

Problem:

What I'm looking for

what I've tried:


Solution

  • What I needed to do was:

    SwaggerConfiguration oasConfig = new SwaggerConfiguration()
        .openApi(baseModel)
        .readerClass(MyCustomReader.class.getName()) // <- HERE
        .prettyPrint(true)
        .resourcePackages(Set.of("my.api.package"));
    
    public class MyCustomReader extends Reader {
    
      @Override
      public OpenAPI read(Class<?> cls,
                          String parentPath, 
                          String parentMethod, 
                          boolean isSubresource,
                          RequestBody parentRequestBody, 
                          ApiResponses apiResponses,
                          Set<String> parentTags,
                          List<Parameter> parentParameters,
                          Set<Class<?>> scannedResources)
     {
        OpenAPI openAPI = super.read(cls, parentPath, parentMethod, isSubresource,                parentRequestBody, apiResponses,
          parentTags, parentParameters, scannedResources);
        return populateMissingDescriptions(openAPI);
      }
    
      public static OpenAPI populateMissingDescriptions(OpenAPI openAPI) {
        if (openAPI.getPaths() != null) {
          for (Entry<String, PathItem> entry : openAPI.getPaths().entrySet()) {
            String path = entry.getKey();
            PathItem pathItem = entry.getValue();
            for (Operation operation : pathItem.readOperations()) {
              if (operation.getResponses() != null) {
                for (Entry<String, ApiResponse> e : operation.getResponses().entrySet()) {
                  String status = e.getKey();
                  ApiResponse response = e.getValue();
                  if (response.getDescription() == null) {
                    response.setDescription("");
                  }
                }
              }
            }
          }
        }
        return openAPI;
      }
    }