swagger-core
swagger-core copied to clipboard
Polymorphic arrays are not properly documented using Swagger Annotations
Given the following endpoint and response classes:
@Path("/test_polymorphic")
@Tag(name = "/test_polymorphic")
public interface PolymorphicEntityEndpoints {
@GET
@Path("/{id}")
@Operation(summary = "Get the entity by id")
EntityResponse get(
@Parameter(description = "The id of the entity to be retrieved.", required = true)
@PathParam("id") String id);
}
public class EntityResponse {
@JsonProperty("id")
String id;
@JsonProperty("name")
String name;
@JsonProperty("pets")
List<? extends PetResponse> pets;
}
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type")
@JsonSubTypes({
@Type(value = DogResponse.class, name = "DOG"),
@Type(value = CatResponse.class, name = "CAT"),
})
@Schema(discriminatorProperty = "type", discriminatorMapping = {
@DiscriminatorMapping(value = "DOG", schema = DogResponse.class),
@DiscriminatorMapping(value = "CAT", schema = CatResponse.class)
}, anyOf = {DogResponse.class, CatResponse.class})
public abstract class PetResponse {
protected String id;
protected PetType type;
@JsonProperty("id")
public String getId() {
return id;
}
@JsonProperty("type")
public PetType getType() {
return type;
}
}
public class DogResponse extends PetResponse {
String weight;
@JsonProperty("weight")
public String getWeight() {
return weight;
}
}
public class CatResponse extends PetResponse {
String color;
@JsonProperty("color")
public String getColor() {
return color;
}
}
generates the following OpenAPI description:
"/test_polymorphic/{id}" : {
"get" : {
"tags" : [ "/test_polymorphic" ],
"summary" : "Get the entity by id",
"operationId" : "get_1",
"parameters" : [ {
"name" : "id",
"in" : "path",
"description" : "The id of the entity to be retrieved.",
"required" : true,
"schema" : {
"type" : "string"
}
} ],
"responses" : {
"default" : {
"description" : "default response",
"content" : {
"application/json" : {
"schema" : {
"$ref" : "#/components/schemas/EntityResponse"
}
}
}
}
}
}
}
"EntityResponse" : {
"type" : "object",
"properties" : {
"id" : {
"type" : "string"
},
"name" : {
"type" : "string"
},
"pets" : {
"type" : "array",
"items" : {
"$ref" : "#/components/schemas/PetResponse"
}
}
}
},
"PetResponse" : {
"type" : "object",
"properties" : {
"id" : {
"type" : "string"
},
"type" : {
"type" : "string",
"enum" : [ "DOG", "CAT" ]
}
},
"discriminator" : {
"propertyName" : "type",
"mapping" : {
"DOG" : "#/components/schemas/DogResponse",
"CAT" : "#/components/schemas/CatResponse"
}
},
"anyOf" : [ {
"$ref" : "#/components/schemas/DogResponse"
}, {
"$ref" : "#/components/schemas/CatResponse"
} ]
},
"CatResponse" : {
"type" : "object",
"allOf" : [ {
"$ref" : "#/components/schemas/PetResponse"
}, {
"type" : "object",
"properties" : {
"color" : {
"type" : "string"
}
}
} ]
},
"DogResponse" : {
"type" : "object",
"allOf" : [ {
"$ref" : "#/components/schemas/PetResponse"
}, {
"type" : "object",
"properties" : {
"weight" : {
"type" : "string"
}
}
} ]
}
As you can see the pets polymorphic array is generated as:
"pets" : {
"type" : "array",
"items" : {
"$ref" : "#/components/schemas/PetResponse"
}
}
And the parent schema PetResponse has the anyOf defined on it.
This results in the swagger-ui to show it wrongly. See the attached screenshots. The example doesn't display the parent fields. The schema shows the parent fields and then says that there will be anyOf subclasses.

I found this ticket on the OpenAPI https://github.com/OAI/OpenAPI-Specification/issues/1627 which says that the polymorphic arrays should be represented differently.
After manually changing the pets polymorphic array definition to:
"pets" : {
"type" : "array",
"items" : {
"anyOf" : [ {
"$ref" : "#/components/schemas/DogResponse"
}, {
"$ref" : "#/components/schemas/CatResponse"
} ]
}
}
the swagger-ui started to represent it correctly (I also had to remove the anyOf from the @Schema annotation on the PetResponse)

I assume that there is a bug in the ModelResolver for defining polymorphic arrays. Please advice. I also found this TODO comment in the ModelResolver on line 387:

I'm using the latest swagger-core and swagger-jaxrs2 (version 2.1.6)