Search code examples
javaspring-bootmavenswaggerswagger-ui

Using Java annotations, can I use the oneOf annotation to override abstract field to override Swagger documentation creation?


I'm using Swagger UI to create documentation for my Spring Boot API. The result is almost as I want, but the "oneOf" annotation is causing a small problem.

First of all, I've added the springdoc-openapi-starter-webmvc-ui as a dependency in my pom.xml file:

<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
    <version>2.3.0</version>
</dependency>

Some of my schema definitions for the Swagger UI are extended from abstract classes. This is where I'm having my problem.

The API is meant to return a list of search results, packed in a pagination object. The search results are abstractly defined as follows (I omitted schema field descriptions, for easier reading):

@Data
public abstract class SearchItemData {
    private String externalId;
    private String type;
    private String name;
    private String description;
    @JsonFormat(shape = JsonFormat.Shape.STRING, timezone = "Europe/Copenhagen")
    private Date published;
    private String address;
    private String phase;
    private Long estimatedSum;
    private Long buildingArea;
    private String projectStart;
    private String projectEnd;
    private List<RoleData> roles;
}

I have two classes extending SearchItemData:

@EqualsAndHashCode(callSuper = true)
@Data
public class ProjectData extends SearchItemData {
    // ...
}

@EqualsAndHashCode(callSuper = true)
@Data
public class ProcurementData extends SearchItemData {
    // ...
}

When getting a result from the endpoint, it's packed in a SearchItemPage object:

@Data
public class SearchItemPage {
    int page;
    int pageCount;
    int pageSize;
    long totalResults;
    // TODO anyOf
    @Schema(
            description = "Array of projects and/or procurements, matching the search parameters",
            oneOf = { ProjectData.class, ProcurementData.class }
    )
    List<SearchItemData> results;
    Long procurementCount;
    Long projectCount;
}

The problem is, when deploying the application, and opening the generated Swagger UI, I get the following:

Scheme example for abstract class SearchItemData

The schema for ProjectData and ProcurementData are correct, but it seems like inheritance doesn't really go well with the "oneOf" annotation. I can see the logic in how it goes wrong, but I'm having trouble finding a solution.

I've tried defining the list as List<? extends SearchItemData>, which didn't really do anything.

I've seen some people use interfaces instead, which would require some workaround for me, and I'm not really sure it would work here. And I can't find a way to override the automatic scheme definition creation, as I'm lacking some use case examples in the documentation for the library.


Solution

  • You might need to add something like

    @Schema(allOf = ParentClass.class)
    

    in the derived classes and

    @Schema(subTypes = {DerivedClassA.class, DerivedClassB.class},
        discriminatorProperty = "type",
        discriminatorMapping = {
                @DiscriminatorMapping(value = "typeA", schema = DerivedClassA.class),
                @DiscriminatorMapping(value = "typeB", schema = DerivedClassB.class)
        })
    

    in the parent class.