Skip to content

Commit 582674d

Browse files
authored
Merge pull request #85 from damianw/fix-allof
improve allOf merging for composite schemas
2 parents 9dc158e + 2765aaa commit 582674d

File tree

6 files changed

+314
-8
lines changed

6 files changed

+314
-8
lines changed

src/main/java/com/qdesrame/openapi/diff/compare/SchemaDiff.java

Lines changed: 171 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,19 @@
1010
import com.qdesrame.openapi.diff.utils.RefPointer;
1111
import com.qdesrame.openapi.diff.utils.RefType;
1212
import io.swagger.v3.oas.models.Components;
13+
import io.swagger.v3.oas.models.ExternalDocumentation;
1314
import io.swagger.v3.oas.models.media.ArraySchema;
1415
import io.swagger.v3.oas.models.media.ComposedSchema;
16+
import io.swagger.v3.oas.models.media.Discriminator;
1517
import io.swagger.v3.oas.models.media.Schema;
16-
import java.util.*;
18+
import io.swagger.v3.oas.models.media.XML;
19+
import java.util.ArrayList;
20+
import java.util.HashSet;
21+
import java.util.LinkedHashMap;
22+
import java.util.List;
23+
import java.util.Map;
24+
import java.util.Objects;
25+
import java.util.Optional;
1726

1827
public class SchemaDiff extends ReferenceDiffCache<Schema, ChangedSchema> {
1928

@@ -87,10 +96,9 @@ protected static Schema resolveComposedSchema(Components components, Schema sche
8796
protected static Schema addSchema(Schema<?> schema, Schema<?> fromSchema) {
8897
if (fromSchema.getProperties() != null) {
8998
if (schema.getProperties() == null) {
90-
schema.setProperties(fromSchema.getProperties());
91-
} else {
92-
schema.getProperties().putAll(fromSchema.getProperties());
99+
schema.setProperties(new LinkedHashMap<>());
93100
}
101+
schema.getProperties().putAll(fromSchema.getProperties());
94102
}
95103

96104
if (fromSchema.getRequired() != null) {
@@ -100,7 +108,165 @@ protected static Schema addSchema(Schema<?> schema, Schema<?> fromSchema) {
100108
schema.getRequired().addAll(fromSchema.getRequired());
101109
}
102110
}
103-
// TODO copy other things from fromSchema
111+
112+
if (fromSchema.getReadOnly() != null) {
113+
schema.setReadOnly(fromSchema.getReadOnly());
114+
}
115+
if (fromSchema.getWriteOnly() != null) {
116+
schema.setWriteOnly(fromSchema.getWriteOnly());
117+
}
118+
if (fromSchema.getDeprecated() != null) {
119+
schema.setDeprecated(fromSchema.getDeprecated());
120+
}
121+
if (fromSchema.getExclusiveMaximum() != null) {
122+
schema.setExclusiveMaximum(fromSchema.getExclusiveMaximum());
123+
}
124+
if (fromSchema.getExclusiveMinimum() != null) {
125+
schema.setExclusiveMinimum(fromSchema.getExclusiveMinimum());
126+
}
127+
if (fromSchema.getNullable() != null) {
128+
schema.setNullable(fromSchema.getNullable());
129+
}
130+
if (fromSchema.getUniqueItems() != null) {
131+
schema.setUniqueItems(fromSchema.getUniqueItems());
132+
}
133+
if (fromSchema.getDescription() != null) {
134+
schema.setDescription(fromSchema.getDescription());
135+
}
136+
if (fromSchema.getFormat() != null) {
137+
schema.setFormat(fromSchema.getFormat());
138+
}
139+
if (fromSchema.getType() != null) {
140+
schema.setType(fromSchema.getType());
141+
}
142+
if (fromSchema.getEnum() != null) {
143+
if (schema.getEnum() == null) {
144+
schema.setEnum(new ArrayList<>());
145+
}
146+
//noinspection unchecked
147+
schema.getEnum().addAll((List) fromSchema.getEnum());
148+
}
149+
if (fromSchema.getExtensions() != null) {
150+
if (schema.getExtensions() == null) {
151+
schema.setExtensions(new LinkedHashMap<>());
152+
}
153+
schema.getExtensions().putAll(fromSchema.getExtensions());
154+
}
155+
if (fromSchema.getDiscriminator() != null) {
156+
if (schema.getDiscriminator() == null) {
157+
schema.setDiscriminator(new Discriminator());
158+
}
159+
final Discriminator discriminator = schema.getDiscriminator();
160+
final Discriminator fromDiscriminator = fromSchema.getDiscriminator();
161+
if (fromDiscriminator.getPropertyName() != null) {
162+
discriminator.setPropertyName(fromDiscriminator.getPropertyName());
163+
}
164+
if (fromDiscriminator.getMapping() != null) {
165+
if (discriminator.getMapping() == null) {
166+
discriminator.setMapping(new LinkedHashMap<>());
167+
}
168+
discriminator.getMapping().putAll(fromDiscriminator.getMapping());
169+
}
170+
}
171+
if (fromSchema.getTitle() != null) {
172+
schema.setTitle(fromSchema.getTitle());
173+
}
174+
if (fromSchema.getName() != null) {
175+
schema.setName(fromSchema.getName());
176+
}
177+
if (fromSchema.getAdditionalProperties() != null) {
178+
schema.setAdditionalProperties(fromSchema.getAdditionalProperties());
179+
}
180+
if (fromSchema.getDefault() != null) {
181+
schema.setDefault(fromSchema.getDefault());
182+
}
183+
if (fromSchema.getExample() != null) {
184+
schema.setExample(fromSchema.getExample());
185+
}
186+
if (fromSchema.getExternalDocs() != null) {
187+
if (schema.getExternalDocs() == null) {
188+
schema.setExternalDocs(new ExternalDocumentation());
189+
}
190+
final ExternalDocumentation externalDocs = schema.getExternalDocs();
191+
final ExternalDocumentation fromExternalDocs = fromSchema.getExternalDocs();
192+
if (fromExternalDocs.getDescription() != null) {
193+
externalDocs.setDescription(fromExternalDocs.getDescription());
194+
}
195+
if (fromExternalDocs.getExtensions() != null) {
196+
if (externalDocs.getExtensions() == null) {
197+
externalDocs.setExtensions(new LinkedHashMap<>());
198+
}
199+
externalDocs.getExtensions().putAll(fromExternalDocs.getExtensions());
200+
}
201+
if (fromExternalDocs.getUrl() != null) {
202+
externalDocs.setUrl(fromExternalDocs.getUrl());
203+
}
204+
}
205+
if (fromSchema.getMaximum() != null) {
206+
schema.setMaximum(fromSchema.getMaximum());
207+
}
208+
if (fromSchema.getMinimum() != null) {
209+
schema.setMinimum(fromSchema.getMinimum());
210+
}
211+
if (fromSchema.getMaxItems() != null) {
212+
schema.setMaxItems(fromSchema.getMaxItems());
213+
}
214+
if (fromSchema.getMinItems() != null) {
215+
schema.setMinItems(fromSchema.getMinItems());
216+
}
217+
if (fromSchema.getMaxProperties() != null) {
218+
schema.setMaxProperties(fromSchema.getMaxProperties());
219+
}
220+
if (fromSchema.getMinProperties() != null) {
221+
schema.setMinProperties(fromSchema.getMinProperties());
222+
}
223+
if (fromSchema.getMaxLength() != null) {
224+
schema.setMaxLength(fromSchema.getMaxLength());
225+
}
226+
if (fromSchema.getMinLength() != null) {
227+
schema.setMinLength(fromSchema.getMinLength());
228+
}
229+
if (fromSchema.getMultipleOf() != null) {
230+
schema.setMultipleOf(fromSchema.getMultipleOf());
231+
}
232+
if (fromSchema.getNot() != null) {
233+
if (schema.getNot() == null) {
234+
schema.setNot(addSchema(new Schema(), fromSchema.getNot()));
235+
} else {
236+
addSchema(schema.getNot(), fromSchema.getNot());
237+
}
238+
}
239+
if (fromSchema.getPattern() != null) {
240+
schema.setPattern(fromSchema.getPattern());
241+
}
242+
if (fromSchema.getXml() != null) {
243+
if (schema.getXml() == null) {
244+
schema.setXml(new XML());
245+
}
246+
final XML xml = schema.getXml();
247+
final XML fromXml = fromSchema.getXml();
248+
if (fromXml.getAttribute() != null) {
249+
xml.setAttribute(fromXml.getAttribute());
250+
}
251+
if (fromXml.getName() != null) {
252+
xml.setName(fromXml.getName());
253+
}
254+
if (fromXml.getNamespace() != null) {
255+
xml.setNamespace(fromXml.getNamespace());
256+
}
257+
if (fromXml.getExtensions() != null) {
258+
if (xml.getExtensions() == null) {
259+
xml.setExtensions(new LinkedHashMap<>());
260+
}
261+
xml.getExtensions().putAll(fromXml.getExtensions());
262+
}
263+
if (fromXml.getPrefix() != null) {
264+
xml.setPrefix(fromXml.getPrefix());
265+
}
266+
if (fromXml.getWrapped() != null) {
267+
xml.setWrapped(fromXml.getWrapped());
268+
}
269+
}
104270
return schema;
105271
}
106272

src/test/java/com/qdesrame/openapi/test/AllOfDiffTest.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ public class AllOfDiffTest {
1111
private final String OPENAPI_DOC1 = "allOf_diff_1.yaml";
1212
private final String OPENAPI_DOC2 = "allOf_diff_2.yaml";
1313
private final String OPENAPI_DOC3 = "allOf_diff_3.yaml";
14+
private final String OPENAPI_DOC4 = "allOf_diff_4.yaml";
1415

1516
@Test
1617
public void testDiffSame() {
@@ -23,7 +24,12 @@ public void testDiffSameWithAllOf() {
2324
}
2425

2526
@Test
26-
public void testDiffDifferent() {
27+
public void testDiffDifferent1() {
2728
assertOpenApiChangedEndpoints(OPENAPI_DOC1, OPENAPI_DOC3);
2829
}
30+
31+
@Test
32+
public void testDiffDifferent2() {
33+
assertOpenApiChangedEndpoints(OPENAPI_DOC1, OPENAPI_DOC4);
34+
}
2935
}

src/test/resources/allOf_diff_1.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,9 @@ components:
108108
- pet_type
109109
properties:
110110
pet_type:
111-
type: string
111+
nullable: false
112+
allOf:
113+
- type: string
112114
Cat:
113115
description: Cat class
114116
allOf:

src/test/resources/allOf_diff_2.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ components:
101101
- pet_type
102102
properties:
103103
pet_type:
104+
nullable: false
104105
type: string
105106
Cat:
106107
description: Cat class

src/test/resources/allOf_diff_3.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,9 @@ components:
105105
- pet_type
106106
properties:
107107
pet_type:
108-
type: string
108+
nullable: false
109+
allOf:
110+
- type: string
109111
Cat:
110112
description: Cat class
111113
allOf:

src/test/resources/allOf_diff_4.yaml

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
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+
email: apiteam@swagger.io
15+
license:
16+
name: Apache 2.0
17+
url: 'http://www.apache.org/licenses/LICENSE-2.0.html'
18+
tags:
19+
- name: pet
20+
description: Everything about your Pets
21+
externalDocs:
22+
description: Find out more
23+
url: 'http://swagger.io'
24+
- name: store
25+
description: Access to Petstore orders
26+
- name: user
27+
description: Operations about user
28+
externalDocs:
29+
description: Find out more about our store
30+
url: 'http://swagger.io'
31+
paths:
32+
/pet/findByStatus:
33+
get:
34+
tags:
35+
- pet
36+
summary: Finds Pets by status
37+
description: Multiple status values can be provided with comma separated strings
38+
operationId: findPetsByStatus
39+
parameters:
40+
- name: status
41+
in: query
42+
description: Status values that need to be considered for filter
43+
required: true
44+
explode: true
45+
schema:
46+
type: array
47+
items:
48+
type: string
49+
enum:
50+
- available
51+
- pending
52+
- sold
53+
default: available
54+
responses:
55+
'200':
56+
description: successful operation
57+
content:
58+
application/json:
59+
schema:
60+
type: object
61+
properties:
62+
pets:
63+
type: array
64+
items:
65+
$ref: '#/components/schemas/Cat'
66+
'400':
67+
description: Invalid status value
68+
security:
69+
- petstore_auth:
70+
- 'write:pets'
71+
- 'read:pets'
72+
externalDocs:
73+
description: Find out more about Swagger
74+
url: 'http://swagger.io'
75+
components:
76+
requestBodies:
77+
Pet:
78+
content:
79+
application/json:
80+
schema:
81+
$ref: '#/components/schemas/Pet'
82+
description: Pet object that needs to be added to the store
83+
required: true
84+
securitySchemes:
85+
petstore_auth:
86+
type: oauth2
87+
flows:
88+
implicit:
89+
authorizationUrl: 'http://petstore.swagger.io/oauth/dialog'
90+
scopes:
91+
'write:pets': modify pets in your account
92+
'read:pets': read your pets
93+
api_key:
94+
type: apiKey
95+
name: api_key
96+
in: header
97+
schemas:
98+
BasePet:
99+
type: object
100+
properties:
101+
pet_color:
102+
type: string
103+
Pet:
104+
allOf:
105+
- $ref: '#/components/schemas/BasePet'
106+
type: object
107+
required:
108+
- pet_type
109+
properties:
110+
pet_type:
111+
nullable: false
112+
allOf:
113+
- type: number
114+
Cat:
115+
description: Cat class
116+
allOf:
117+
- $ref: '#/components/schemas/Pet'
118+
type: object
119+
properties:
120+
name:
121+
type: string
122+
Dog:
123+
description: Dog class
124+
allOf:
125+
- $ref: '#/components/schemas/Pet'
126+
type: object
127+
properties:
128+
bark:
129+
type: string

0 commit comments

Comments
 (0)