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:
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.
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.