'How to programmatically include a custom property into spec generated by springdoc-openapi?

I have an endpoint that accepts and sends back objects of the form {a: 1, b: 2, c:3} where either b or c is missing. To precise, admissible objects are {a: 1, b: 2}, {a: 1, c:3} where the values are free to choose.

@RestController
@RequestMapping("/v42")
public class MyAPI {

    @PostMapping("/subsets")
    public Subset getSubsets(@RequestParam Subset subset) {

        return subset;
    }

}

Internally the JSON object is parsed into a subclass of Subset:

@JsonDeserialize(using = SubsetDeserializer.class)
public abstract class Subset {
}

@AllArgsConstructor
public class SubsetAB extends Subset {
    int a,b;
}
@AllArgsConstructor
public class SubsetAC extends Subset {
    int a,c;
}

But since the parent class has no fields the generated spec does not list them:

paths:
  /v42/subsets:
    post:
      tags:
      - pet-api
      operationId: getSubset
      parameters:
      - name: subset
        in: query
        required: true
        schema:
          $ref: '#/components/schemas/com.myservice.api.v42.Subset'
      responses:
        200:
          description: OK
          content:
            '*/*':
              schema:
                $ref: '#/components/schemas/com.myservice.api.v42.Subset'
...
components:
  schemas:
    com.myservice.api.v42.Subset:
      type: object

How can I annotate my Subset class so that if shows as having either the form SubsetAB or SubsetAC?

I've tried:

Defining my own examples:

@PostMapping("/subsets")
@ApiResponses(value = {
    @ApiResponse(responseCode = "200", description = "Subset that comes back", content = {
        @Content(mediaType = "application/json", examples = {
            @ExampleObject(name = "subsetAB", description = "With A and B", value = "{\"a\": 1, \"b\": 2}"),
            @ExampleObject(name = "subsetAC", description = "With A and C", value = "{\"a\": 1, \"c\": 3}")
        })
    })
})
public Subset getSubset(@io.swagger.v3.oas.annotations.parameters.RequestBody(content = @Content(examples = {
        @ExampleObject(name = "subsetAB", description = "With A and B", value = "{\"a\": 1, \"b\": 2}"),
        @ExampleObject(name = "subsetAC", description = "With A and C", value = "{\"a\": 1, \"c\": 3}")
})) @RequestBody Subset subset) {

    return subset;
}

This works pretty good already:

paths:
  /v42/subsets:
    post:
      tags:
      - pet-api
      operationId: getSubset
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/com.myservice.api.v42.Subset'
            examples:
              subsetAB:
                description: With A and B
                value:
                  a: 1
                  b: 2
              subsetAC:
                description: With A and C
                value:
                  a: 1
                  c: 3
        required: true
      responses:
        200:
          description: Subset that comes back
          content:
            application/json:
              examples:
                subsetAB:
                  description: With A and B
                  value:
                    a: 1
                    b: 2
                subsetAC:
                  description: With A and C
                  value:
                    a: 1
                    c: 3
...
components:
  schemas:
    com.myservice.api.v42.Subset:
      type: object

I have examples for input and output and can also see them nicely displayed in the /swagger-ui.html endpoint. However, the schema definition is still empty. And it would be convenient to just define and reference the schemas and have the examples generated automatically.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source