swagger-api / swagger-api/swagger-core
Incorrect mapping of sub-classes when nested as member of another sub-class
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 7.5k
- Forks
- 2.3k
- Avg merge
- 18h 1m
- Merged PRs (30d)
- 10
Description
Note: This issue was posted in springdoc-openapi first. It was closed, since the issue seams to be located in swagger-core.
Describe the bug
- Inherited sub-classes are not mapped correctly if they are nested in a sub-class that by itself is derived from a super class.
- I'd expect the mapping to be
onOf()which is true for the nested class itself, but not for the member. - See the example to make things clear:
To Reproduce
Steps to reproduce the behavior:
- Spring Boot starter parent, version 3.0.2
- Spring Doc modules starter-webmvc-ui and starter-common in version 2.0.2.
Here's an example controller:
@RestController
@RequestMapping(path = "/v1/test", produces = MediaType.APPLICATION_JSON_VALUE)
public class TestOpenApiError {
@GetMapping("/a")
public A testGetA() {
return null;
}
@GetMapping("/b")
public B testGetB() {
return null;
}
@GetMapping("/c")
public C testGetC() {
return null;
}
@Schema(
description = "Some out class",
subTypes = { A1.class, A2.class, },
discriminatorProperty = "@type",
discriminatorMapping = {
@DiscriminatorMapping(schema = A1.class, value = "A1"),
@DiscriminatorMapping(schema = A2.class, value = "A2"),
}
)
public class A {}
public class A1 extends A {}
public class A2 extends A {
public List<? extends B> listOfBs;
}
@Schema(
description = "Some nested class",
subTypes = { B1.class, B2.class, },
discriminatorProperty = "@type",
discriminatorMapping = {
@DiscriminatorMapping(schema = B1.class, value = "B1"),
@DiscriminatorMapping(schema = B2.class, value = "B2"),
}
)
public class B {}
public class B1 extends B {}
public class B2 extends B {}
public class C {
public List<? extends B> listOfBs;
}
}
I have three classes A, B, and C. A1 and A2 are derived from A. B1 and B2 are derived from B.
B as list is member of A2 (nested in a class that is derived, too) and B as list is member of C (not nested in an inheritance)
This is the generated outcome fragment for this as yml
B:
type: object
description: Some nested class
discriminator:
propertyName: '@type'
mapping:
B1: '#/components/schemas/B1'
B2: '#/components/schemas/B2'
B1:
type: object
allOf:
- $ref: '#/components/schemas/B'
B2:
type: object
allOf:
- $ref: '#/components/schemas/B'
C:
type: object
properties:
listOfBs:
type: array
items:
oneOf:
- $ref: '#/components/schemas/B'
- $ref: '#/components/schemas/B1'
- $ref: '#/components/schemas/B2'
A:
type: object
description: Some out class
discriminator:
propertyName: '@type'
mapping:
A1: '#/components/schemas/A1'
A2: '#/components/schemas/A2'
A1:
type: object
allOf:
- $ref: '#/components/schemas/A'
A2:
type: object
allOf:
- $ref: '#/components/schemas/A'
- type: object
properties:
listOfBs:
type: array
items:
$ref: '#/components/schemas/B'
When B is member of C the generation is as expected. Is maps to oneOf. As expected:
C:
type: object
properties:
listOfBs:
type: array
items:
oneOf:
- $ref: '#/components/schemas/B'
- $ref: '#/components/schemas/B1'
- $ref: '#/components/schemas/B2'
When B is member of A2 it just refers to an array of type B. No oneOf mapping:
A2:
type: object
allOf:
- $ref: '#/components/schemas/A'
- type: object
properties:
listOfBs:
type: array
items:
$ref: '#/components/schemas/B'
Expected behavior
I'd expect A2 to me mapped like this:
A2:
type: object
allOf:
- $ref: '#/components/schemas/A'
- type: object
properties:
listOfBs:
type: array
items:
oneOf:
- $ref: '#/components/schemas/B'
- $ref: '#/components/schemas/B1'
- $ref: '#/components/schemas/B2'
Maybe I'm doing something wrong. Maybe somebody can confirm, that this is a real issue.
Thx for any help.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the TestOpenApiError reproducer and generate the OpenAPI YAML for the C and A2 cases. Compare the listOfBs schemas, using the expected A2 output as the completion criterion: the nested member should emit the same oneOf mapping as C.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, openapi, spring-boot
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100