Skip to content

Commit 4a40fc3

Browse files
authored
Merge pull request #414 from RepreZen/task/306
[#306] OpenAPI v3: Validation for Link#operationRef values
2 parents 233a5e5 + 5068ec1 commit 4a40fc3

File tree

16 files changed

+317
-126
lines changed

16 files changed

+317
-126
lines changed

com.reprezen.swagedit.core/src/com/reprezen/swagedit/core/json/references/JsonReferenceCollector.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public Map<AbstractNode, JsonReference> collect(URI baseURI, Model model) {
4444
final Map<AbstractNode, JsonReference> references = Maps.newHashMap();
4545

4646
for (AbstractNode node : model.allNodes()) {
47-
if (JsonReference.isReference(node)) {
47+
if (factory.isReference(node)) {
4848
JsonReference reference = factory.createSimpleReference(baseURI, node.get(PROPERTY));
4949
if (reference == null) {
5050
reference = factory.create(node);
@@ -57,5 +57,4 @@ public Map<AbstractNode, JsonReference> collect(URI baseURI, Model model) {
5757

5858
return references;
5959
}
60-
6160
}

com.reprezen.swagedit.core/src/com/reprezen/swagedit/core/json/references/JsonReferenceFactory.java

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@
2121
import com.google.common.base.Strings;
2222
import com.reprezen.swagedit.core.model.AbstractNode;
2323
import com.reprezen.swagedit.core.model.Model;
24+
import com.reprezen.swagedit.core.model.ValueNode;
2425
import com.reprezen.swagedit.core.utils.URLUtils;
2526

26-
2727
/**
2828
* JSON Reference Factory
2929
*
@@ -37,21 +37,20 @@ public JsonReference create(AbstractNode node) {
3737
return new JsonReference(null, null, false, false, false, node);
3838
}
3939

40-
if (node.isObject() && node.get(JsonReference.PROPERTY) != null) {
41-
node = node.get(JsonReference.PROPERTY);
40+
ValueNode value = getReferenceValue(node);
41+
if (value != null) {
42+
return doCreate((String) value.getValue(), value);
43+
} else {
44+
return null;
4245
}
43-
44-
return doCreate((String) node.asValue().getValue(), node);
4546
}
4647

4748
public JsonReference create(JsonNode node) {
4849
if (node == null || node.isMissingNode()) {
4950
return new JsonReference(null, null, false, false, false, node);
5051
}
5152

52-
String text = node.isTextual() ? node.asText() : node.get(PROPERTY).asText();
53-
54-
return doCreate(text, node);
53+
return doCreate(getReferenceValue(node), node);
5554
}
5655

5756
public JsonReference create(ScalarNode node) {
@@ -70,7 +69,7 @@ public JsonReference create(ScalarNode node) {
7069
* @return reference
7170
*/
7271
public JsonReference createSimpleReference(URI baseURI, AbstractNode valueNode) {
73-
if (valueNode.isArray() || valueNode.isObject()) {
72+
if (valueNode == null || valueNode.isArray() || valueNode.isObject()) {
7473
return null;
7574
}
7675

@@ -133,4 +132,22 @@ public JsonReference doCreate(String value, Object source) {
133132
return new JsonReference(uri, pointer, absolute, local, warnings, source);
134133
}
135134

135+
protected Boolean isReference(AbstractNode node) {
136+
return JsonReference.isReference(node);
137+
}
138+
139+
protected ValueNode getReferenceValue(AbstractNode node) {
140+
if (node.isValue()) {
141+
return node.asValue();
142+
}
143+
AbstractNode value = node.get(PROPERTY);
144+
if (value != null && value.isValue()) {
145+
return value.asValue();
146+
}
147+
return null;
148+
}
149+
150+
protected String getReferenceValue(JsonNode node) {
151+
return node.isTextual() ? node.asText() : node.get(PROPERTY).asText();
152+
}
136153
}

com.reprezen.swagedit.core/src/com/reprezen/swagedit/core/json/references/JsonReferenceValidator.java

Lines changed: 22 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
*******************************************************************************/
1111
package com.reprezen.swagedit.core.json.references;
1212

13+
import static com.reprezen.swagedit.core.validation.Messages.error_invalid_reference;
14+
import static com.reprezen.swagedit.core.validation.Messages.error_invalid_reference_type;
15+
import static com.reprezen.swagedit.core.validation.Messages.error_missing_reference;
16+
import static com.reprezen.swagedit.core.validation.Messages.warning_simple_reference;
1317
import static org.eclipse.core.resources.IMarker.SEVERITY_ERROR;
1418
import static org.eclipse.core.resources.IMarker.SEVERITY_WARNING;
1519

@@ -18,15 +22,12 @@
1822
import java.util.Map;
1923
import java.util.Set;
2024

21-
import org.eclipse.core.resources.IMarker;
22-
2325
import com.fasterxml.jackson.databind.JsonNode;
2426
import com.google.common.collect.Sets;
2527
import com.reprezen.swagedit.core.editor.JsonDocument;
2628
import com.reprezen.swagedit.core.model.AbstractNode;
2729
import com.reprezen.swagedit.core.model.Model;
2830
import com.reprezen.swagedit.core.schema.TypeDefinition;
29-
import com.reprezen.swagedit.core.validation.Messages;
3031
import com.reprezen.swagedit.core.validation.SwaggerError;
3132

3233
/**
@@ -58,13 +59,13 @@ protected Collection<? extends SwaggerError> doValidate(URI baseURI, JsonDocumen
5859
JsonReference reference = references.get(node);
5960

6061
if (reference instanceof JsonReference.SimpleReference) {
61-
errors.add(createReferenceError(SEVERITY_WARNING, Messages.warning_simple_reference, reference));
62+
errors.add(createReferenceError(SEVERITY_WARNING, warning_simple_reference, reference));
6263
} else if (reference.isInvalid()) {
63-
errors.add(createReferenceError(SEVERITY_ERROR, Messages.error_invalid_reference, reference));
64+
errors.add(createReferenceError(SEVERITY_ERROR, error_invalid_reference, reference));
6465
} else if (reference.isMissing(doc, baseURI)) {
65-
errors.add(createReferenceError(SEVERITY_WARNING, Messages.error_missing_reference, reference));
66+
errors.add(createReferenceError(SEVERITY_WARNING, error_missing_reference, reference));
6667
} else if (reference.containsWarning()) {
67-
errors.add(createReferenceError(SEVERITY_WARNING, Messages.error_invalid_reference, reference));
68+
errors.add(createReferenceError(SEVERITY_WARNING, error_invalid_reference, reference));
6869
} else {
6970
validateType(doc, baseURI, node, reference, errors);
7071
}
@@ -84,47 +85,36 @@ protected Collection<? extends SwaggerError> doValidate(URI baseURI, JsonDocumen
8485
* @param errors
8586
* current set of errors
8687
*/
87-
private void validateType(JsonDocument doc, URI baseURI, AbstractNode node, JsonReference reference,
88+
protected void validateType(JsonDocument doc, URI baseURI, AbstractNode node, JsonReference reference,
8889
Set<SwaggerError> errors) {
89-
if (node == null) {
90-
return;
91-
}
9290

93-
Model model = doc.getModel();
91+
AbstractNode target = findTarget(doc, baseURI, reference);
9492
TypeDefinition type = node.getType();
93+
boolean isValidType = type != null && type.validate(target);
9594

96-
AbstractNode nodeValue = node.get(JsonReference.PROPERTY);
97-
String pointer = (String) nodeValue.asValue().getValue();
98-
AbstractNode valueNode = model.find(pointer);
95+
if (!isValidType) {
96+
errors.add(createReferenceError(SEVERITY_WARNING, error_invalid_reference_type, reference));
97+
}
98+
}
99+
100+
protected AbstractNode findTarget(JsonDocument doc, URI baseURI, JsonReference reference) {
101+
Model model = doc.getModel();
102+
AbstractNode valueNode = model.find(reference.getPointer());
99103

100104
if (valueNode == null) {
101105
// Try to load the referenced node from an external document
102106
JsonNode externalDoc = reference.getDocument(doc, baseURI);
103107
if (externalDoc != null) {
104108
try {
105109
Model externalModel = Model.parse(model.getSchema(), externalDoc);
106-
107-
int pos = pointer.indexOf("#");
108-
if (pos == -1) {
109-
valueNode = externalModel.getRoot();
110-
} else {
111-
valueNode = externalModel.find(pointer.substring(pos, pointer.length()));
112-
}
113-
114-
if (valueNode == null) {
115-
return;
116-
}
110+
valueNode = externalModel.find(reference.getPointer());
117111
} catch (Exception e) {
118112
// fail to parse the model or the pointer
119-
return;
113+
return null;
120114
}
121115
}
122116
}
123-
124-
if (!type.validate(valueNode)) {
125-
errors.add(
126-
createReferenceError(IMarker.SEVERITY_WARNING, Messages.error_invalid_reference_type, reference));
127-
}
117+
return valueNode;
128118
}
129119

130120
protected SwaggerError createReferenceError(int severity, String message, JsonReference reference) {

com.reprezen.swagedit.core/src/com/reprezen/swagedit/core/model/AbstractNode.java

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,25 +76,53 @@ public AbstractNode get(String property) {
7676
*
7777
* @return true if object
7878
*/
79-
public abstract boolean isObject();
79+
public boolean isObject() {
80+
return false;
81+
}
8082

8183
/**
8284
* Returns true if the node is an array.
8385
*
8486
* @return true if array
8587
*/
86-
public abstract boolean isArray();
88+
public boolean isArray() {
89+
return false;
90+
}
8791

92+
/**
93+
* Returns true if the node is a value
94+
*
95+
* @return true if value
96+
*/
97+
public boolean isValue() {
98+
return false;
99+
}
100+
101+
/**
102+
* Returns the current node as an {@link ObjectNode} if it is an instance, or null otherwise.
103+
*
104+
* @return node
105+
*/
88106
public ObjectNode asObject() {
89-
return (ObjectNode) this;
107+
return null;
90108
}
91109

110+
/**
111+
* Returns the current node as an {@link ArrayNode} if it is an instance, or null otherwise.
112+
*
113+
* @return node
114+
*/
92115
public ArrayNode asArray() {
93-
return (ArrayNode) this;
116+
return null;
94117
}
95118

119+
/**
120+
* Returns the current node as an {@link ValueNode} if it is an instance, or null otherwise.
121+
*
122+
* @return node
123+
*/
96124
public ValueNode asValue() {
97-
return (ValueNode) this;
125+
return null;
98126
}
99127

100128
/**

com.reprezen.swagedit.core/src/com/reprezen/swagedit/core/model/ArrayNode.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ public AbstractNode get(int pos) {
2929
}
3030

3131
@Override
32-
public boolean isObject() {
33-
return false;
32+
public ArrayNode asArray() {
33+
return this;
3434
}
3535

3636
@Override

com.reprezen.swagedit.core/src/com/reprezen/swagedit/core/model/ObjectNode.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ public boolean isObject() {
5050
}
5151

5252
@Override
53-
public boolean isArray() {
54-
return false;
53+
public ObjectNode asObject() {
54+
return this;
5555
}
5656

5757
@Override

com.reprezen.swagedit.core/src/com/reprezen/swagedit/core/model/ValueNode.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ public class ValueNode extends AbstractNode {
2323
}
2424

2525
@Override
26-
public boolean isObject() {
27-
return false;
26+
public boolean isValue() {
27+
return true;
2828
}
2929

3030
@Override
31-
public boolean isArray() {
32-
return false;
31+
public ValueNode asValue() {
32+
return this;
3333
}
3434

3535
public Object getValue() {

com.reprezen.swagedit.core/src/com/reprezen/swagedit/core/validation/Messages.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ public class Messages extends NLS {
4343
public static String error_scope_should_not_be_empty;
4444
public static String error_invalid_scope_reference;
4545
public static String error_invalid_operation_id;
46+
public static String error_invalid_operation_ref;
4647

4748
public static String error_array_missing_items;
4849
public static String error_object_type_missing;

com.reprezen.swagedit.core/src/com/reprezen/swagedit/core/validation/messages.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ Security requirements for oauth or openIdConnect schemes must specify a list of
5050
error_invalid_scope_reference = "%s" does not match any scope name defined in the %s security scheme.
5151
error_invalid_operation_id = Invalid operationId. \n\
5252
This operationId does not match any existing and resolvable operation.
53+
error_invalid_operation_ref = Invalid operationRef. \n\
54+
This operationRef does not match any existing and resolvable operation.
5355

5456
# yaml
5557
error_yaml_parser_indentation = Unable to parse content, an incorrect indentation may be the cause.

com.reprezen.swagedit.openapi3.tests/src/com/reprezen/swagedit/openapi3/utils/Mocks.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,10 @@
2525
import com.fasterxml.jackson.databind.JsonNode;
2626
import com.reprezen.swagedit.core.json.references.JsonDocumentManager;
2727
import com.reprezen.swagedit.core.json.references.JsonReference;
28-
import com.reprezen.swagedit.core.json.references.JsonReferenceFactory;
2928
import com.reprezen.swagedit.core.model.AbstractNode;
3029
import com.reprezen.swagedit.openapi3.editor.OpenApi3Document;
30+
import com.reprezen.swagedit.openapi3.validation.OpenApi3ReferenceValidator;
31+
import com.reprezen.swagedit.openapi3.validation.OpenApi3ReferenceValidator.OpenApi3ReferenceFactory;
3132

3233
public class Mocks {
3334

@@ -37,11 +38,11 @@ public static ITextViewer mockTextViewer(OpenApi3Document document) {
3738
return viewer;
3839
}
3940

40-
public static JsonReferenceFactory mockJsonReferenceFactory(final Map<URI, JsonNode> entries) {
41+
public static OpenApi3ReferenceFactory mockJsonReferenceFactory(final Map<URI, JsonNode> entries) {
4142
final IFile file = mock(IFile.class);
4243
when(file.exists()).thenReturn(true);
4344

44-
return new JsonReferenceFactory() {
45+
return new OpenApi3ReferenceValidator.OpenApi3ReferenceFactory() {
4546
public JsonReference create(AbstractNode node) {
4647
JsonReference ref = super.create(node);
4748
ref.setDocumentManager(new JsonDocumentManager() {

0 commit comments

Comments
 (0)