Skip to content

Commit

Permalink
Merge pull request everit-org#398 from dab-libs/master
Browse files Browse the repository at this point in the history
Fixes the issue everit-org#382: The 'default' can't be used in 'oneOf'
  • Loading branch information
erosb authored Jan 17, 2021
2 parents 060a8e0 + 5642592 commit e918632
Show file tree
Hide file tree
Showing 10 changed files with 232 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ public ValidationException inContextOfSchema(Schema schema, Runnable task) {
}
}

@Override
Object getState() {
return failureCount();
}

@Override
boolean isChanged(Object oldState) {
return !oldState.equals(failureCount());
}

int failureCount() {
return failures.size();
}
Expand Down
17 changes: 14 additions & 3 deletions core/src/main/java/org/everit/json/schema/ObjectSchema.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ private static final Regexp toRegexp(String pattern) {

private Schema propertyNameSchema;

public boolean oneOrMoreDefaultProperty = false;

public Builder additionalProperties(boolean additionalProperties) {
this.additionalProperties = additionalProperties;
return this;
Expand All @@ -76,6 +78,7 @@ public Builder addPropertySchema(String propName, Schema schema) {
requireNonNull(propName, "propName cannot be null");
requireNonNull(schema, "schema cannot be null");
propertySchemas.put(propName, schema);
oneOrMoreDefaultProperty |= schema.hasDefaultValue();
return this;
}

Expand Down Expand Up @@ -189,6 +192,8 @@ private static <K, V> Map<K, V> copyMap(Map<K, V> original) {

private final Map<Regexp, Schema> patternProperties;

private final boolean oneOrMoreDefaultProperty;

/**
* Constructor.
*
Expand All @@ -214,6 +219,7 @@ public ObjectSchema(Builder builder) {
this.requiresObject = builder.requiresObject;
this.patternProperties = copyMap(builder.patternProperties);
this.propertyNameSchema = builder.propertyNameSchema;
this.oneOrMoreDefaultProperty = builder.oneOrMoreDefaultProperty;
}

public Integer getMaxProperties() {
Expand Down Expand Up @@ -274,6 +280,10 @@ public boolean requiresObject() {
return requiresObject;
}

boolean hasDefaultProperty() {
return oneOrMoreDefaultProperty;
}

@Override
public boolean definesProperty(String field) {
field = field.replaceFirst("^#", "").replaceFirst("^/", "");
Expand Down Expand Up @@ -347,6 +357,7 @@ public boolean equals(Object o) {
Objects.equals(schemaDependencies, that.schemaDependencies) &&
Objects.equals(patternProperties, that.patternProperties) &&
Objects.equals(propertyNameSchema, that.propertyNameSchema) &&
oneOrMoreDefaultProperty == that.oneOrMoreDefaultProperty &&
super.equals(that);
} else {
return false;
Expand All @@ -355,9 +366,9 @@ public boolean equals(Object o) {

@Override
public int hashCode() {
return Objects.hash(super.hashCode(), propertySchemas, propertyNameSchema, additionalProperties, schemaOfAdditionalProperties,
requiredProperties,
minProperties, maxProperties, propertyDependencies, schemaDependencies, requiresObject, patternProperties);
return Objects.hash(super.hashCode(), propertySchemas, propertyNameSchema, additionalProperties,
schemaOfAdditionalProperties, requiredProperties, minProperties, maxProperties, propertyDependencies,
schemaDependencies, requiresObject, patternProperties, oneOrMoreDefaultProperty);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import static org.everit.json.schema.loader.OrgJsonUtil.getNames;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

Expand Down Expand Up @@ -33,7 +34,15 @@ public ObjectSchemaValidatingVisitor(Object subject, ValidatingVisitor owner) {
objSubject = (JSONObject) subject;
objectSize = objSubject.length();
this.schema = objectSchema;
Object failureState = owner.getFailureState();
Set<String> objSubjectKeys = null;
if (objectSchema.hasDefaultProperty()) {
objSubjectKeys = new HashSet<>(objSubject.keySet());
}
super.visitObjectSchema(objectSchema);
if (owner.isFailureStateChanged(failureState) && objectSchema.hasDefaultProperty()) {
objSubject.keySet().retainAll(objSubjectKeys);
}
}
}

Expand Down
13 changes: 8 additions & 5 deletions core/src/main/java/org/everit/json/schema/ValidatingVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,9 @@
import static java.util.stream.Collectors.joining;
import static org.everit.json.schema.EnumSchema.toJavaValue;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

import org.everit.json.schema.event.CombinedSchemaMatchEvent;
import org.everit.json.schema.event.CombinedSchemaMismatchEvent;
Expand Down Expand Up @@ -215,6 +210,14 @@ void failure(ValidationException exc) {
failureReporter.failure(exc);
}

Object getFailureState() {
return failureReporter.getState();
}

boolean isFailureStateChanged(Object olState) {
return failureReporter.isChanged(olState);
}

boolean passesTypeCheck(Class<?> expectedType, boolean schemaRequiresType, Boolean nullable) {
if (isNull(subject)) {
if (schemaRequiresType && !Boolean.TRUE.equals(nullable)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,12 @@ ValidationException inContextOfSchema(Schema schema, Runnable task) {
}

abstract void validationFinished();

Object getState() {
return null;
}

boolean isChanged(Object oldState) {
return false;
}
}
53 changes: 53 additions & 0 deletions core/src/test/java/org/everit/json/schema/DefaultInOneOfTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package org.everit.json.schema;

import org.everit.json.schema.loader.SchemaLoader;
import org.json.JSONArray;
import org.json.JSONObject;
import org.json.JSONTokener;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.io.InputStream;

import static org.everit.json.schema.TestSupport.loadAsV6;
import static org.junit.jupiter.api.Assertions.*;

public class DefaultInOneOfTest {

private static final ResourceLoader LOADER = ResourceLoader.DEFAULT;

@Test
public void defaultInFirstOneOf() {
JSONObject jsonSchema = LOADER.readObj("default-in-first-oneof-schema.json");
JSONObject jsonSpecification = LOADER.readObj("default-in-oneof.json");
Schema schema = SchemaLoader
.builder()
.useDefaults(true)
.schemaJson(jsonSchema)
.build()
.load()
.build();
assertDoesNotThrow(() -> schema.validate(jsonSpecification));
assertTrue(jsonSpecification.getJSONObject("parameter1").has("allowEmptyValue"));
assertFalse(jsonSpecification.getJSONObject("parameter1").getBoolean("allowEmptyValue"));
assertFalse(jsonSpecification.getJSONObject("parameter2").has("allowEmptyValue"));
}

@Test
public void defaultInLastOneOf() {
JSONObject jsonSchema = LOADER.readObj("default-in-last-oneof-schema.json");
JSONObject jsonSpecification = LOADER.readObj("default-in-oneof.json");
Schema schema = SchemaLoader
.builder()
.useDefaults(true)
.schemaJson(jsonSchema)
.build()
.load()
.build();
assertDoesNotThrow(() -> schema.validate(jsonSpecification));
assertTrue(jsonSpecification.getJSONObject("parameter1").has("allowEmptyValue"));
assertFalse(jsonSpecification.getJSONObject("parameter1").getBoolean("allowEmptyValue"));
assertFalse(jsonSpecification.getJSONObject("parameter2").has("allowEmptyValue"));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ public void configurationPropagationTest() throws URISyntaxException {
} catch (ValidationException e) {
assertThat(e.toJSON(), sameJsonAs(LOADER.readObj("expected-exception.json")));
}
assertEquals(42, instance.get("propWithDefault"));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{
"title": "A Bug Schema is a part for Swagger 2.0 API.",
"id": "http://bug-schema.org/schema.json#",
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"required": [
"parameter1",
"parameter2"
],
"additionalProperties": false,
"properties": {
"parameter1": {
"$ref": "#/definitions/nonBodyParameter"
},
"parameter2": {
"$ref": "#/definitions/nonBodyParameter"
}
},
"definitions": {
"nonBodyParameter": {
"type": "object",
"required": [
"in"
],
"oneOf": [
{
"$ref": "#/definitions/queryParameterSubSchema"
},
{
"$ref": "#/definitions/pathParameterSubSchema"
}
]
},
"queryParameterSubSchema": {
"additionalProperties": false,
"properties": {
"in": {
"type": "string",
"enum": [
"query"
]
},
"allowEmptyValue": {
"type": "boolean",
"default": false
}
}
},
"pathParameterSubSchema": {
"additionalProperties": false,
"properties": {
"in": {
"type": "string",
"enum": [
"path"
]
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{
"title": "A Bug Schema is a part for Swagger 2.0 API.",
"id": "http://bug-schema.org/schema.json#",
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"required": [
"parameter1",
"parameter2"
],
"additionalProperties": false,
"properties": {
"parameter1": {
"$ref": "#/definitions/nonBodyParameter"
},
"parameter2": {
"$ref": "#/definitions/nonBodyParameter"
}
},
"definitions": {
"nonBodyParameter": {
"type": "object",
"required": [
"in"
],
"oneOf": [
{
"$ref": "#/definitions/pathParameterSubSchema"
},
{
"$ref": "#/definitions/queryParameterSubSchema"
}
]
},
"queryParameterSubSchema": {
"additionalProperties": false,
"properties": {
"in": {
"type": "string",
"enum": [
"query"
]
},
"allowEmptyValue": {
"type": "boolean",
"default": false
}
}
},
"pathParameterSubSchema": {
"additionalProperties": false,
"properties": {
"in": {
"type": "string",
"enum": [
"path"
]
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"parameter1": {
"in": "query"
},
"parameter2": {
"in": "path"
}
}

0 comments on commit e918632

Please sign in to comment.