Skip to content

Commit 8eca893

Browse files
authored
Merge pull request #1333 from keenanpepper/discriminator-resolve-subtypes
Follow discriminator mappings to resolve subtypes
2 parents 24b6120 + 4121b65 commit 8eca893

19 files changed

+829
-0
lines changed

modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/processors/ExternalRefProcessor.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import io.swagger.v3.oas.models.links.Link;
1010
import io.swagger.v3.oas.models.media.ArraySchema;
1111
import io.swagger.v3.oas.models.media.ComposedSchema;
12+
import io.swagger.v3.oas.models.media.Discriminator;
1213
import io.swagger.v3.oas.models.media.MediaType;
1314
import io.swagger.v3.oas.models.media.ObjectSchema;
1415
import io.swagger.v3.oas.models.media.Schema;
@@ -150,6 +151,8 @@ public String processRefToExternalSchema(String $ref, RefFormat refFormat) {
150151

151152
processProperties(subProps,file);
152153

154+
processDiscriminator(schema.getDiscriminator(),file);
155+
153156
if(schema.getAdditionalProperties() != null && schema.getAdditionalProperties() instanceof Schema){
154157
Schema additionalProperty = (Schema) schema.getAdditionalProperties();
155158
if (additionalProperty.get$ref() != null) {
@@ -223,6 +226,21 @@ private void processProperties(Map<String, Schema> properties, String file) {
223226
}
224227
}
225228

229+
private void processDiscriminator(Discriminator d, String file) {
230+
if (d != null && d.getMapping() != null) {
231+
processDiscriminatorMapping(d.getMapping(), file);
232+
}
233+
}
234+
235+
private void processDiscriminatorMapping(Map<String, String> mapping, String file) {
236+
for (String key : mapping.keySet()) {
237+
String ref = mapping.get(key);
238+
Schema subtype = new Schema().$ref(ref);
239+
processSchema(subtype, file);
240+
mapping.put(key, subtype.get$ref());
241+
}
242+
}
243+
226244
public String processRefToExternalResponse(String $ref, RefFormat refFormat) {
227245
String renamedRef = cache.getRenamedRef($ref);
228246
if(renamedRef != null) {

modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/processors/SchemaProcessor.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,19 @@ public void processSchemaType(Schema schema){
6161
processAdditionalProperties(schema);
6262

6363
}
64+
if (schema.getDiscriminator() != null) {
65+
processDiscriminatorSchema(schema);
66+
}
67+
68+
}
6469

70+
private void processDiscriminatorSchema(Schema schema) {
71+
if (schema.getDiscriminator() != null && schema.getDiscriminator().getMapping() != null) {
72+
Map<String, String> mapping = schema.getDiscriminator().getMapping();
73+
for (String ref : mapping.values()) {
74+
processReferenceSchema(new Schema().$ref(ref));
75+
}
76+
}
6577
}
6678

6779
private void processAdditionalProperties(Object additionalProperties) {

modules/swagger-parser-v3/src/test/java/io/swagger/v3/parser/test/OpenAPIV3ParserTest.java

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2325,4 +2325,69 @@ public void testDuplicateHttpStatusCodesYaml() {
23252325
private static int getDynamicPort() {
23262326
return new Random().ints(10000, 20000).findFirst().getAsInt();
23272327
}
2328+
2329+
@Test
2330+
public void testDiscriminatorSingleFileNoMapping() throws Exception {
2331+
OpenAPI openAPI = new OpenAPIV3Parser().read("./discriminator-mapping-resolution/single-file-no-mapping.yaml");
2332+
Assert.assertNotNull(openAPI);
2333+
Schema cat = openAPI.getComponents().getSchemas().get("Cat");
2334+
Assert.assertNotNull(cat);
2335+
}
2336+
2337+
@Test
2338+
public void testDiscriminatorSeparateFileNoMapping() throws Exception {
2339+
OpenAPI openAPI = new OpenAPIV3Parser().read("./discriminator-mapping-resolution/main-no-mapping.yaml");
2340+
Assert.assertNotNull(openAPI);
2341+
Schema cat = openAPI.getComponents().getSchemas().get("Cat");
2342+
Assert.assertNull(cat); // FIXME, issue #970 still exists in this form
2343+
}
2344+
2345+
@Test
2346+
public void testDiscriminatorSingleFilePlainMapping() throws Exception {
2347+
OpenAPI openAPI = new OpenAPIV3Parser().read("./discriminator-mapping-resolution/single-file-plain-mapping.yaml");
2348+
Assert.assertNotNull(openAPI);
2349+
Schema cat = openAPI.getComponents().getSchemas().get("Cat");
2350+
Assert.assertNotNull(cat);
2351+
}
2352+
2353+
@Test
2354+
public void testDiscriminatorSeparateFilePlainMapping() throws Exception {
2355+
OpenAPI openAPI = new OpenAPIV3Parser().read("./discriminator-mapping-resolution/main-plain-mapping.yaml");
2356+
Assert.assertNotNull(openAPI);
2357+
Schema cat = openAPI.getComponents().getSchemas().get("Cat");
2358+
Assert.assertNotNull(cat);
2359+
}
2360+
2361+
@Test
2362+
public void testDiscriminatorSingleFileInternalMapping() throws Exception {
2363+
OpenAPI openAPI = new OpenAPIV3Parser().read("./discriminator-mapping-resolution/single-file-internal-mapping.yaml");
2364+
Assert.assertNotNull(openAPI);
2365+
Schema cat = openAPI.getComponents().getSchemas().get("Cat");
2366+
Assert.assertNotNull(cat);
2367+
}
2368+
2369+
@Test
2370+
public void testDiscriminatorSeparateFileInternalMapping() throws Exception {
2371+
OpenAPI openAPI = new OpenAPIV3Parser().read("./discriminator-mapping-resolution/main-internal-mapping.yaml");
2372+
Assert.assertNotNull(openAPI);
2373+
Schema cat = openAPI.getComponents().getSchemas().get("Cat");
2374+
Assert.assertNotNull(cat);
2375+
}
2376+
2377+
@Test
2378+
public void testDiscriminatorSameFileExternalMapping() throws Exception {
2379+
OpenAPI openAPI = new OpenAPIV3Parser().read("./discriminator-mapping-resolution/main-external-mapping.yaml");
2380+
Assert.assertNotNull(openAPI);
2381+
Schema cat = openAPI.getComponents().getSchemas().get("Cat");
2382+
Assert.assertNotNull(cat);
2383+
}
2384+
2385+
@Test
2386+
public void testDiscriminatorSeparateFileExternalMapping() throws Exception {
2387+
OpenAPI openAPI = new OpenAPIV3Parser().read("./discriminator-mapping-resolution/main-external-mapping-3files.yaml");
2388+
Assert.assertNotNull(openAPI);
2389+
Schema cat = openAPI.getComponents().getSchemas().get("Cat");
2390+
Assert.assertNotNull(cat);
2391+
}
2392+
23282393
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Cat:
2+
allOf:
3+
- $ref: '#/components/schemas/Pet'
4+
# all other properties specific to a `Cat`
5+
type: object
6+
properties:
7+
name:
8+
type: string
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Dog:
2+
allOf:
3+
- $ref: '#/components/schemas/Pet'
4+
# all other properties specific to a `Dog`
5+
type: object
6+
properties:
7+
bark:
8+
type: string
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
openapi: 3.0.0
2+
servers:
3+
- url: 'http://petstore.swagger.io/v2'
4+
info:
5+
description: >-
6+
This is a sample server Petstore server. You can find out more about
7+
Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net,
8+
#swagger](http://swagger.io/irc/). For this sample, you can use the api key
9+
`special-key` to test the authorization filters.
10+
version: 1.0.0
11+
title: Swagger Petstore
12+
termsOfService: 'http://swagger.io/terms/'
13+
contact:
14+
15+
license:
16+
name: Apache 2.0
17+
url: 'http://www.apache.org/licenses/LICENSE-2.0.html'
18+
paths:
19+
/pet/findByStatus:
20+
get:
21+
tags:
22+
- pet
23+
summary: Finds Pets by status
24+
description: Multiple status values can be provided with comma separated strings
25+
operationId: findPetsByStatus
26+
parameters:
27+
- name: status
28+
in: query
29+
description: Status values that need to be considered for filter
30+
required: true
31+
explode: true
32+
schema:
33+
type: array
34+
items:
35+
type: string
36+
enum:
37+
- available
38+
- pending
39+
- sold
40+
default: available
41+
responses:
42+
'200':
43+
description: successful operation
44+
content:
45+
application/json:
46+
schema:
47+
type: object
48+
properties:
49+
pets:
50+
type: array
51+
items:
52+
$ref: 'parent-external-mapping.yaml#/components/schemas/Pet'
53+
'400':
54+
description: Invalid status value
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
openapi: 3.0.0
2+
servers:
3+
- url: 'http://petstore.swagger.io/v2'
4+
info:
5+
description: >-
6+
This is a sample server Petstore server. You can find out more about
7+
Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net,
8+
#swagger](http://swagger.io/irc/). For this sample, you can use the api key
9+
`special-key` to test the authorization filters.
10+
version: 1.0.0
11+
title: Swagger Petstore
12+
termsOfService: 'http://swagger.io/terms/'
13+
contact:
14+
15+
license:
16+
name: Apache 2.0
17+
url: 'http://www.apache.org/licenses/LICENSE-2.0.html'
18+
paths:
19+
/pet/findByStatus:
20+
get:
21+
tags:
22+
- pet
23+
summary: Finds Pets by status
24+
description: Multiple status values can be provided with comma separated strings
25+
operationId: findPetsByStatus
26+
parameters:
27+
- name: status
28+
in: query
29+
description: Status values that need to be considered for filter
30+
required: true
31+
explode: true
32+
schema:
33+
type: array
34+
items:
35+
type: string
36+
enum:
37+
- available
38+
- pending
39+
- sold
40+
default: available
41+
responses:
42+
'200':
43+
description: successful operation
44+
content:
45+
application/json:
46+
schema:
47+
type: object
48+
properties:
49+
pets:
50+
type: array
51+
items:
52+
$ref: '#/components/schemas/Pet'
53+
'400':
54+
description: Invalid status value
55+
components:
56+
schemas:
57+
Pet:
58+
type: object
59+
required:
60+
- pet_type
61+
properties:
62+
pet_type:
63+
type: string
64+
discriminator:
65+
propertyName: pet_type
66+
mapping:
67+
Cat: 'Cat.yaml'
68+
Dog: 'Dog.yaml'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
openapi: 3.0.0
2+
servers:
3+
- url: 'http://petstore.swagger.io/v2'
4+
info:
5+
description: >-
6+
This is a sample server Petstore server. You can find out more about
7+
Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net,
8+
#swagger](http://swagger.io/irc/). For this sample, you can use the api key
9+
`special-key` to test the authorization filters.
10+
version: 1.0.0
11+
title: Swagger Petstore
12+
termsOfService: 'http://swagger.io/terms/'
13+
contact:
14+
15+
license:
16+
name: Apache 2.0
17+
url: 'http://www.apache.org/licenses/LICENSE-2.0.html'
18+
paths:
19+
/pet/findByStatus:
20+
get:
21+
tags:
22+
- pet
23+
summary: Finds Pets by status
24+
description: Multiple status values can be provided with comma separated strings
25+
operationId: findPetsByStatus
26+
parameters:
27+
- name: status
28+
in: query
29+
description: Status values that need to be considered for filter
30+
required: true
31+
explode: true
32+
schema:
33+
type: array
34+
items:
35+
type: string
36+
enum:
37+
- available
38+
- pending
39+
- sold
40+
default: available
41+
responses:
42+
'200':
43+
description: successful operation
44+
content:
45+
application/json:
46+
schema:
47+
type: object
48+
properties:
49+
pets:
50+
type: array
51+
items:
52+
$ref: 'pet-internal-mapping.yaml#/components/schemas/Pet'
53+
'400':
54+
description: Invalid status value
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
openapi: 3.0.0
2+
servers:
3+
- url: 'http://petstore.swagger.io/v2'
4+
info:
5+
description: >-
6+
This is a sample server Petstore server. You can find out more about
7+
Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net,
8+
#swagger](http://swagger.io/irc/). For this sample, you can use the api key
9+
`special-key` to test the authorization filters.
10+
version: 1.0.0
11+
title: Swagger Petstore
12+
termsOfService: 'http://swagger.io/terms/'
13+
contact:
14+
15+
license:
16+
name: Apache 2.0
17+
url: 'http://www.apache.org/licenses/LICENSE-2.0.html'
18+
paths:
19+
/pet/findByStatus:
20+
get:
21+
tags:
22+
- pet
23+
summary: Finds Pets by status
24+
description: Multiple status values can be provided with comma separated strings
25+
operationId: findPetsByStatus
26+
parameters:
27+
- name: status
28+
in: query
29+
description: Status values that need to be considered for filter
30+
required: true
31+
explode: true
32+
schema:
33+
type: array
34+
items:
35+
type: string
36+
enum:
37+
- available
38+
- pending
39+
- sold
40+
default: available
41+
responses:
42+
'200':
43+
description: successful operation
44+
content:
45+
application/json:
46+
schema:
47+
type: object
48+
properties:
49+
pets:
50+
type: array
51+
items:
52+
$ref: 'pet-no-mapping-oneof.yaml#/components/schemas/Pet'
53+
'400':
54+
description: Invalid status value

0 commit comments

Comments
 (0)