Skip to content

Commit e0d18c4

Browse files
authored
Merge pull request #50 from quen2404/improve-extension-support
Improve extension support
2 parents 3e14c85 + 816f4e2 commit e0d18c4

29 files changed

+276
-65
lines changed

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

+2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ public Optional<ChangedApiResponse> diff(ApiResponses left, ApiResponses right,
3535
.ifPresent(changedResponse -> resps.put(responseCode, changedResponse));
3636
}
3737
changedApiResponse.setChangedResponses(resps);
38+
openApiDiff.getExtensionsDiff().diff(left.getExtensions(), right.getExtensions(), context)
39+
.ifPresent(changedApiResponse::setChangedExtensions);
3840
return isChanged(changedApiResponse);
3941
}
4042
}

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

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.qdesrame.openapi.diff.compare;
22

3+
import com.qdesrame.openapi.diff.model.Change;
34
import com.qdesrame.openapi.diff.model.Changed;
45
import com.qdesrame.openapi.diff.model.DiffContext;
56

@@ -11,5 +12,10 @@ public interface ExtensionDiff {
1112

1213
String getName();
1314

14-
Optional<Changed> diff(Object left, Object right, DiffContext context);
15+
Optional<Changed> diff(Change extension, DiffContext context);
16+
17+
default boolean isParentApplicable(Change.Type type, Object object, Object extension, DiffContext context) {
18+
return true;
19+
}
20+
1521
}

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

+43-9
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
package com.qdesrame.openapi.diff.compare;
22

3+
import com.qdesrame.openapi.diff.model.Change;
4+
import com.qdesrame.openapi.diff.model.Changed;
5+
import com.qdesrame.openapi.diff.model.CompatibleChanged;
36
import com.qdesrame.openapi.diff.model.DiffContext;
47
import com.qdesrame.openapi.diff.model.schema.ChangedExtensions;
58

69
import java.util.*;
10+
import java.util.function.Function;
711

812
import static com.qdesrame.openapi.diff.utils.ChangedUtils.isChanged;
913

@@ -21,23 +25,53 @@ public ExtensionsDiff(OpenApiDiff openApiDiff) {
2125
}
2226
}
2327

28+
public boolean isParentApplicable(Change.Type type, Object parent, Map<String, Object> extensions, DiffContext context) {
29+
if (extensions.size() == 0) {
30+
return true;
31+
}
32+
return extensions.entrySet().stream()
33+
.map(entry -> executeExtension(entry.getKey(), extensionDiff -> extensionDiff.isParentApplicable(type, parent, entry.getValue(), context)))
34+
.allMatch(aBoolean -> aBoolean.orElse(true));
35+
}
36+
37+
public Optional<ExtensionDiff> getExtensionDiff(String name) {
38+
return extensionsDiff.stream()
39+
.filter(diff -> ("x-" + diff.getName()).equals(name))
40+
.findFirst();
41+
}
42+
43+
public <T> Optional<T> executeExtension(String name, Function<ExtensionDiff, T> predicate) {
44+
return getExtensionDiff(name)
45+
.map(extensionDiff -> extensionDiff.setOpenApiDiff(openApiDiff))
46+
.map(predicate);
47+
}
48+
49+
public Optional<ChangedExtensions> diff(Map<String, Object> left, Map<String, Object> right) {
50+
return this.diff(left, right, null);
51+
}
52+
2453
public Optional<ChangedExtensions> diff(Map<String, Object> left, Map<String, Object> right, DiffContext context) {
2554
if (null == left) left = new LinkedHashMap<>();
2655
if (null == right) right = new LinkedHashMap<>();
2756
ChangedExtensions changedExtensions = new ChangedExtensions(left, new LinkedHashMap<>(right), context);
28-
changedExtensions.getIncreased().putAll(right);
2957
for (String key : left.keySet()) {
30-
if (changedExtensions.getIncreased().containsKey(key)) {
31-
Optional<ExtensionDiff> extensionDiff = extensionsDiff.stream()
32-
.filter(diff -> ("x-" + diff.getName()).equals(key)).findFirst();
33-
Object leftValue = left.get(key);
34-
Object rightValue = changedExtensions.getIncreased().remove(key);
35-
extensionDiff.ifPresent(diff -> diff.setOpenApiDiff(openApiDiff).diff(leftValue, rightValue, context)
36-
.ifPresent(changed -> changedExtensions.getChanged().put(key, changed)));
58+
Object leftValue = left.get(key);
59+
if (right.containsKey(key)) {
60+
Object rightValue = right.remove(key);
61+
executeExtensionDiff(key, Change.changed(leftValue, rightValue), context)
62+
.ifPresent(changed -> changedExtensions.getChanged().put(key, changed));
3763
} else {
38-
changedExtensions.getMissing().put(key, left.get(key));
64+
executeExtensionDiff(key, Change.removed(leftValue), context)
65+
.ifPresent(changed -> changedExtensions.getMissing().put(key, changed));
3966
}
4067
}
68+
right.forEach((key, value) -> executeExtensionDiff(key, Change.added(value), context)
69+
.ifPresent(changed -> changedExtensions.getIncreased().put(key, changed)));
4170
return isChanged(changedExtensions);
4271
}
72+
73+
private Optional<Changed> executeExtensionDiff(String name, Change change, DiffContext context) {
74+
return executeExtension(name, diff -> diff.setOpenApiDiff(openApiDiff).diff(change, context))
75+
.orElse(Optional.of(CompatibleChanged.compatible(change)));
76+
}
4377
}

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ protected Optional<ChangedHeader> computeDiff(HashSet<String> refSet, Header lef
4646
changedHeader.setChangeExplode(getBooleanDiff(left.getExplode(), right.getExplode()));
4747
openApiDiff.getSchemaDiff().diff(new HashSet<>(), left.getSchema(), right.getSchema(), context.copyWithRequired(true)).ifPresent(changedHeader::setChangedSchema);
4848
openApiDiff.getContentDiff().diff(left.getContent(), right.getContent(), context).ifPresent(changedHeader::setChangedContent);
49-
49+
openApiDiff.getExtensionsDiff().diff(left.getExtensions(), right.getExtensions(), context)
50+
.ifPresent(changedHeader::setChangedExtensions);
5051
return isChanged(changedHeader);
5152
}
5253

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

+9-1
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
import com.qdesrame.openapi.diff.model.ChangedOAuthFlow;
44
import io.swagger.v3.oas.models.security.OAuthFlow;
55

6+
import java.util.Map;
67
import java.util.Objects;
78
import java.util.Optional;
89

910
import static com.qdesrame.openapi.diff.utils.ChangedUtils.isChanged;
11+
import static java.util.Optional.ofNullable;
1012

1113
/**
1214
* Created by adarsh.sharma on 12/01/18.
@@ -18,14 +20,20 @@ public OAuthFlowDiff(OpenApiDiff openApiDiff) {
1820
this.openApiDiff = openApiDiff;
1921
}
2022

23+
private static Map<String, Object> getExtensions(OAuthFlow oAuthFlow) {
24+
return ofNullable(oAuthFlow).map(OAuthFlow::getExtensions).orElse(null);
25+
}
26+
2127
public Optional<ChangedOAuthFlow> diff(OAuthFlow left, OAuthFlow right) {
2228
ChangedOAuthFlow changedOAuthFlow = new ChangedOAuthFlow(left, right);
2329
if (left != null && right != null) {
2430
changedOAuthFlow.setChangedAuthorizationUrl(!Objects.equals(left.getAuthorizationUrl(), right.getAuthorizationUrl()));
2531
changedOAuthFlow.setChangedTokenUrl(!Objects.equals(left.getTokenUrl(), right.getTokenUrl()));
2632
changedOAuthFlow.setChangedRefreshUrl(!Objects.equals(left.getRefreshUrl(), right.getRefreshUrl()));
2733
}
28-
34+
openApiDiff.getExtensionsDiff().diff(getExtensions(left), getExtensions(right))
35+
.ifPresent(changedOAuthFlow::setChangedExtensions);
2936
return isChanged(changedOAuthFlow);
3037
}
38+
3139
}

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

+9
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
import com.qdesrame.openapi.diff.model.ChangedOAuthFlows;
44
import io.swagger.v3.oas.models.security.OAuthFlows;
55

6+
import java.util.Map;
67
import java.util.Optional;
78

89
import static com.qdesrame.openapi.diff.utils.ChangedUtils.isChanged;
10+
import static java.util.Optional.ofNullable;
911

1012
/**
1113
* Created by adarsh.sharma on 12/01/18.
@@ -17,6 +19,10 @@ public OAuthFlowsDiff(OpenApiDiff openApiDiff) {
1719
this.openApiDiff = openApiDiff;
1820
}
1921

22+
private static Map<String, Object> getExtensions(OAuthFlows oAuthFlow) {
23+
return ofNullable(oAuthFlow).map(OAuthFlows::getExtensions).orElse(null);
24+
}
25+
2026
public Optional<ChangedOAuthFlows> diff(OAuthFlows left, OAuthFlows right) {
2127
ChangedOAuthFlows changedOAuthFlows = new ChangedOAuthFlows(left, right);
2228
if (left != null && right != null) {
@@ -25,6 +31,9 @@ public Optional<ChangedOAuthFlows> diff(OAuthFlows left, OAuthFlows right) {
2531
openApiDiff.getoAuthFlowDiff().diff(left.getClientCredentials(), right.getClientCredentials()).ifPresent(changedOAuthFlows::setChangedClientCredentialOAuthFlow);
2632
openApiDiff.getoAuthFlowDiff().diff(left.getAuthorizationCode(), right.getAuthorizationCode()).ifPresent(changedOAuthFlows::setChangedAuthorizationCodeOAuthFlow);
2733
}
34+
openApiDiff.getExtensionsDiff().diff(getExtensions(left), getExtensions(right))
35+
.ifPresent(changedOAuthFlows::setChangedExtensions);
2836
return isChanged(changedOAuthFlows);
2937
}
38+
3039
}

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

+10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.qdesrame.openapi.diff.compare;
22

33
import com.qdesrame.openapi.diff.model.*;
4+
import com.qdesrame.openapi.diff.model.schema.ChangedExtensions;
45
import com.qdesrame.openapi.diff.utils.EndpointUtils;
56
import io.swagger.v3.oas.models.OpenAPI;
67
import io.swagger.v3.oas.models.PathItem;
@@ -47,6 +48,8 @@ public class OpenApiDiff {
4748
private List<Endpoint> newEndpoints;
4849
private List<Endpoint> missingEndpoints;
4950
private List<ChangedOperation> changedOperations;
51+
private ChangedExtensions changedExtensions;
52+
5053

5154
/*
5255
* @param oldSpecOpenApi
@@ -105,9 +108,15 @@ private ChangedOpenApi compare() {
105108
changedOperations.addAll(changedPath.getChanged());
106109
});
107110
});
111+
getExtensionsDiff().diff(oldSpecOpenApi.getExtensions(), newSpecOpenApi.getExtensions())
112+
.ifPresent(this::setChangedExtension);
108113
return getChangedOpenApi();
109114
}
110115

116+
private void setChangedExtension(ChangedExtensions changedExtension) {
117+
this.changedExtensions = changedExtension;
118+
}
119+
111120
private void preProcess(OpenAPI openApi) {
112121
List<SecurityRequirement> securityRequirements = openApi.getSecurity();
113122

@@ -132,6 +141,7 @@ private ChangedOpenApi getChangedOpenApi() {
132141
changedOpenApi.setNewSpecOpenApi(newSpecOpenApi);
133142
changedOpenApi.setOldSpecOpenApi(oldSpecOpenApi);
134143
changedOpenApi.setChangedOperations(changedOperations);
144+
changedOpenApi.setChangedExtensions(changedExtensions);
135145
return changedOpenApi;
136146
}
137147

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

+3
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ public Optional<ChangedOperation> diff(Operation oldOperation, Operation newOper
4949
.ifPresent(changedOperation::setChangedSecurityRequirements);
5050
}
5151

52+
openApiDiff.getExtensionsDiff().diff(oldOperation.getExtensions(), newOperation.getExtensions(), context)
53+
.ifPresent(changedOperation::setChangedExtensions);
54+
5255
return isChanged(changedOperation);
5356
}
5457

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ protected Optional<ChangedParameter> computeDiff(HashSet<String> refSet, Paramet
5252
}
5353
openApiDiff.getContentDiff().diff(left.getContent(), right.getContent(), context)
5454
.ifPresent(changedParameter::setChangedContent);
55-
55+
openApiDiff.getExtensionsDiff().diff(left.getExtensions(), right.getExtensions(), context)
56+
.ifPresent(changedParameter::setChangedExtensions);
5657
return isChanged(changedParameter);
5758
}
5859

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

+2
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ public Optional<ChangedPath> diff(PathItem left, PathItem right, DiffContext con
3333
Operation newOperation = newOperationMap.get(method);
3434
openApiDiff.getOperationDiff().diff(oldOperation, newOperation, context.copyWithMethod(method)).ifPresent(changedPath.getChanged()::add);
3535
}
36+
openApiDiff.getExtensionsDiff().diff(left.getExtensions(), right.getExtensions(), context)
37+
.ifPresent(changedPath::setChangedExtensions);
3638
return isChanged(changedPath);
3739
}
3840
}

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

+8
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@
88
import io.swagger.v3.oas.models.parameters.RequestBody;
99

1010
import java.util.HashSet;
11+
import java.util.Map;
1112
import java.util.Objects;
1213
import java.util.Optional;
1314

1415
import static com.qdesrame.openapi.diff.utils.ChangedUtils.isChanged;
16+
import static java.util.Optional.ofNullable;
1517

1618
/**
1719
* Created by adarsh.sharma on 28/12/17.
@@ -30,6 +32,10 @@ public Optional<ChangedRequestBody> diff(RequestBody left, RequestBody right, Di
3032
return cachedDiff(new HashSet<>(), left, right, leftRef, rightRef, context);
3133
}
3234

35+
private static Map<String, Object> getExtensions(RequestBody body) {
36+
return ofNullable(body).map(RequestBody::getExtensions).orElse(null);
37+
}
38+
3339
@Override
3440
protected Optional<ChangedRequestBody> computeDiff(HashSet<String> refSet, RequestBody left, RequestBody right, DiffContext context) {
3541
Content oldRequestContent = new Content();
@@ -59,6 +65,8 @@ protected Optional<ChangedRequestBody> computeDiff(HashSet<String> refSet, Reque
5965
changedRequestBody.setChangeDescription(!Objects.equals(leftDescription, rightDescription));
6066

6167
openApiDiff.getContentDiff().diff(oldRequestContent, newRequestContent, context).ifPresent(changedRequestBody::setChangedContent);
68+
openApiDiff.getExtensionsDiff().diff(getExtensions(left), getExtensions(right), context)
69+
.ifPresent(changedRequestBody::setChangedExtensions);
6270

6371
return isChanged(changedRequestBody);
6472
}

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ protected Optional<ChangedResponse> computeDiff(HashSet<String> refSet, ApiRespo
4242
openApiDiff.getContentDiff().diff(left.getContent(), right.getContent(), context).ifPresent(changedResponse::setChangedContent);
4343
openApiDiff.getHeadersDiff().diff(left.getHeaders(), right.getHeaders(), context).ifPresent(changedResponse::setChangedHeaders);
4444
changedResponse.setChangeDescription(!Objects.equals(left.getDescription(), right.getDescription()));
45-
45+
openApiDiff.getExtensionsDiff().diff(left.getExtensions(), right.getExtensions(), context)
46+
.ifPresent(changedResponse::setChangedExtensions);
4647
return isChanged(changedResponse);
4748
}
4849
}

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

+2
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ protected Optional<ChangedSecurityScheme> computeDiff(HashSet<String> refSet, Se
7070
.getOpenIdConnectUrl()));
7171
break;
7272
}
73+
openApiDiff.getExtensionsDiff().diff(leftSecurityScheme.getExtensions(), rightSecurityScheme.getExtensions(), context)
74+
.ifPresent(changedSecurityScheme::setChangedExtensions);
7375

7476
return Optional.of(changedSecurityScheme);
7577
}

src/main/java/com/qdesrame/openapi/diff/compare/schemadiffresult/SchemaDiffResult.java

+17-7
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.qdesrame.openapi.diff.compare.MapKeyDiff;
44
import com.qdesrame.openapi.diff.compare.OpenApiDiff;
5+
import com.qdesrame.openapi.diff.model.Change;
56
import com.qdesrame.openapi.diff.model.ChangedSchema;
67
import com.qdesrame.openapi.diff.model.DiffContext;
78
import com.qdesrame.openapi.diff.model.ListDiff;
@@ -13,9 +14,9 @@
1314
import lombok.Getter;
1415

1516
import java.util.*;
16-
import java.util.stream.Collectors;
1717

1818
import static com.qdesrame.openapi.diff.utils.ChangedUtils.isChanged;
19+
import static java.util.Optional.ofNullable;
1920

2021
@Getter
2122
public class SchemaDiffResult {
@@ -60,8 +61,8 @@ public Optional<ChangedSchema> diff(HashSet<String> refSet, Components leftCompo
6061

6162
compareAdditionalProperties(refSet, left, right, context);
6263

63-
changedSchema.getIncreasedProperties().putAll(filterProperties(propertyDiff.getIncreased(), context));
64-
changedSchema.getMissingProperties().putAll(filterProperties(propertyDiff.getMissing(), context));
64+
changedSchema.getIncreasedProperties().putAll(filterProperties(Change.Type.ADDED, propertyDiff.getIncreased(), context));
65+
changedSchema.getMissingProperties().putAll(filterProperties(Change.Type.REMOVED, propertyDiff.getMissing(), context));
6566
return isApplicable(context);
6667
}
6768

@@ -73,10 +74,19 @@ protected Optional<ChangedSchema> isApplicable(DiffContext context) {
7374
return isChanged(changedSchema);
7475
}
7576

76-
private Map<String, Schema> filterProperties(Map<String, Schema> properties, DiffContext context) {
77-
return properties.entrySet().stream()
78-
.filter(entry -> isPropertyApplicable(entry.getValue(), context))
79-
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
77+
private Map<String, Schema> filterProperties(Change.Type type, Map<String, Schema> properties, DiffContext context) {
78+
Map<String, Schema> result = new LinkedHashMap<>();
79+
for (Map.Entry<String, Schema> entry : properties.entrySet()) {
80+
if (isPropertyApplicable(entry.getValue(), context)
81+
&& openApiDiff.getExtensionsDiff()
82+
.isParentApplicable(
83+
type,
84+
entry.getValue(),
85+
ofNullable(entry.getValue().getExtensions()).orElse(new LinkedHashMap()), context)) {
86+
result.put(entry.getKey(), entry.getValue());
87+
}
88+
}
89+
return result;
8090
}
8191

8292
private boolean isPropertyApplicable(Schema schema, DiffContext context) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.qdesrame.openapi.diff.model;
2+
3+
import lombok.Getter;
4+
5+
@Getter
6+
public class Change<T> {
7+
private final T oldValue;
8+
private final T newValue;
9+
private final Type type;
10+
11+
private Change(T oldValue, T newValue, Type type) {
12+
this.oldValue = oldValue;
13+
this.newValue = newValue;
14+
this.type = type;
15+
}
16+
17+
public static <T> Change<T> changed(T oldValue, T newValue) {
18+
return new Change<>(oldValue, newValue, Type.CHANGED);
19+
}
20+
21+
public static <T> Change<T> added(T newValue) {
22+
return new Change<>(null, newValue, Type.ADDED);
23+
}
24+
25+
public static <T> Change<T> removed(T oldValue) {
26+
return new Change<>(oldValue, null, Type.REMOVED);
27+
}
28+
29+
public enum Type {
30+
ADDED,
31+
CHANGED,
32+
REMOVED
33+
}
34+
}

0 commit comments

Comments
 (0)