Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions core/src/main/java/org/everit/json/schema/ConditionalSchema.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package org.everit.json.schema;

import java.util.Optional;

/**
* Validator for {@code if}, {@code then}, {@code else} schemas.
*/
public class ConditionalSchema extends Schema {

/**
* Builder class for {@link ConditionalSchema}.
*/
public static class Builder extends Schema.Builder<ConditionalSchema> {
private Schema ifSchema;
private Schema thenSchema;
private Schema elseSchema;

public Builder ifSchema(final Schema ifSchema) {
this.ifSchema = ifSchema;
return this;
}

public Builder thenSchema(final Schema thenSchema) {
this.thenSchema = thenSchema;
return this;
}

public Builder elseSchema(final Schema elseSchema) {
this.elseSchema = elseSchema;
return this;
}

@Override
public ConditionalSchema build() {
return new ConditionalSchema(this);
}
}

public static Builder builder() {
return new Builder();
}

private final Schema ifSchema;
private final Schema thenSchema;
private final Schema elseSchema;

public ConditionalSchema(Builder builder) {
super(builder);
this.ifSchema = builder.ifSchema;
this.thenSchema = builder.thenSchema;
this.elseSchema = builder.elseSchema;
}

public Optional<Schema> getIfSchema() {
return Optional.ofNullable(ifSchema);
}

public Optional<Schema> getThenSchema() {
return Optional.ofNullable(thenSchema);
}

public Optional<Schema> getElseSchema() {
return Optional.ofNullable(elseSchema);
}

@Override
void accept(Visitor visitor) {
visitor.visitConditionalSchema(this);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package org.everit.json.schema;


import java.util.Arrays;

import static java.util.Objects.requireNonNull;

class ConditionalSchemaValidatingVisitor extends Visitor {

private final Object subject;

private final ValidatingVisitor owner;

private ConditionalSchema conditionalSchema;

private ValidationException ifSchemaException;

public ConditionalSchemaValidatingVisitor(Object subject, ValidatingVisitor owner) {
this.subject = subject;
this.owner = requireNonNull(owner, "owner cannot be null");
}

@Override
void visitConditionalSchema(ConditionalSchema conditionalSchema) {
this.conditionalSchema = conditionalSchema;
if (!conditionalSchema.getIfSchema().isPresent() ||
(!conditionalSchema.getThenSchema().isPresent() && !conditionalSchema.getElseSchema().isPresent())) {
return;
}
super.visitConditionalSchema(conditionalSchema);
}

@Override
void visitIfSchema(Schema ifSchema) {
if (conditionalSchema.getIfSchema().isPresent()) {
ifSchemaException = owner.getFailureOfSchema(ifSchema, subject);
}
}

@Override
void visitThenSchema(Schema thenSchema) {
if (ifSchemaException == null) {
ValidationException thenSchemaException = owner.getFailureOfSchema(thenSchema, subject);
if (thenSchemaException != null) {
owner.failure(new ValidationException(conditionalSchema,
new StringBuilder(new StringBuilder("#")),
"input is invalid against the \"then\" schema",
Arrays.asList(thenSchemaException),
"then",
conditionalSchema.getSchemaLocation()));
}
}
}

@Override
void visitElseSchema(Schema elseSchema) {
if (ifSchemaException != null) {
ValidationException elseSchemaException = owner.getFailureOfSchema(elseSchema, subject);
if (elseSchemaException != null) {
owner.failure(new ValidationException(conditionalSchema,
new StringBuilder(new StringBuilder("#")),
"input is invalid against both the \"if\" and \"else\" schema",
Arrays.asList(ifSchemaException, elseSchemaException),
"else",
conditionalSchema.getSchemaLocation()));
}
}
}

}
47 changes: 32 additions & 15 deletions core/src/main/java/org/everit/json/schema/ValidatingVisitor.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package org.everit.json.schema;

import static java.lang.String.format;
import static org.everit.json.schema.EnumSchema.toJavaValue;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.json.JSONObject;
import static java.lang.String.format;
import static org.everit.json.schema.EnumSchema.toJavaValue;

class ValidatingVisitor extends Visitor {

Expand All @@ -32,27 +32,32 @@ void visit(Schema schema) {
this.failureReporter = failureReporter;
}

@Override void visitNumberSchema(NumberSchema numberSchema) {
@Override
void visitNumberSchema(NumberSchema numberSchema) {
numberSchema.accept(new NumberSchemaValidatingVisitor(subject, this));
}

@Override void visitArraySchema(ArraySchema arraySchema) {
@Override
void visitArraySchema(ArraySchema arraySchema) {
arraySchema.accept(new ArraySchemaValidatingVisitor(subject, this));
}

@Override void visitBooleanSchema(BooleanSchema schema) {
@Override
void visitBooleanSchema(BooleanSchema schema) {
if (!(subject instanceof Boolean)) {
failureReporter.failure(Boolean.class, subject);
}
}

@Override void visitNullSchema(NullSchema nullSchema) {
@Override
void visitNullSchema(NullSchema nullSchema) {
if (!(subject == null || subject == JSONObject.NULL)) {
failureReporter.failure("expected: null, found: " + subject.getClass().getSimpleName(), "type");
}
}

@Override void visitConstSchema(ConstSchema constSchema) {
@Override
void visitConstSchema(ConstSchema constSchema) {
if (isNull(subject) && isNull(constSchema.getPermittedValue())) {
return;
}
Expand All @@ -62,7 +67,8 @@ void visit(Schema schema) {
}
}

@Override void visitEnumSchema(EnumSchema enumSchema) {
@Override
void visitEnumSchema(EnumSchema enumSchema) {
Object effectiveSubject = toJavaValue(subject);
for (Object possibleValue : enumSchema.getPossibleValues()) {
if (ObjectComparator.deepEquals(possibleValue, effectiveSubject)) {
Expand All @@ -72,19 +78,22 @@ void visit(Schema schema) {
failureReporter.failure(format("%s is not a valid enum value", subject), "enum");
}

@Override void visitFalseSchema(FalseSchema falseSchema) {
@Override
void visitFalseSchema(FalseSchema falseSchema) {
failureReporter.failure("false schema always fails", "false");
}

@Override void visitNotSchema(NotSchema notSchema) {
@Override
void visitNotSchema(NotSchema notSchema) {
Schema mustNotMatch = notSchema.getMustNotMatch();
ValidationException failure = getFailureOfSchema(mustNotMatch, subject);
if (failure == null) {
failureReporter.failure("subject must not be valid against schema " + mustNotMatch, "not");
}
}

@Override void visitReferenceSchema(ReferenceSchema referenceSchema) {
@Override
void visitReferenceSchema(ReferenceSchema referenceSchema) {
Schema referredSchema = referenceSchema.getReferredSchema();
if (referredSchema == null) {
throw new IllegalStateException("referredSchema must be injected before validation");
Expand All @@ -95,15 +104,18 @@ void visit(Schema schema) {
}
}

@Override void visitObjectSchema(ObjectSchema objectSchema) {
@Override
void visitObjectSchema(ObjectSchema objectSchema) {
objectSchema.accept(new ObjectSchemaValidatingVisitor(subject, this));
}

@Override void visitStringSchema(StringSchema stringSchema) {
@Override
void visitStringSchema(StringSchema stringSchema) {
stringSchema.accept(new StringSchemaValidatingVisitor(subject, this));
}

@Override void visitCombinedSchema(CombinedSchema combinedSchema) {
@Override
void visitCombinedSchema(CombinedSchema combinedSchema) {
List<ValidationException> failures = new ArrayList<>();
Collection<Schema> subschemas = combinedSchema.getSubschemas();
CombinedSchema.ValidationCriterion criterion = combinedSchema.getCriterion();
Expand All @@ -126,6 +138,11 @@ void visit(Schema schema) {
}
}

@Override
void visitConditionalSchema(ConditionalSchema conditionalSchema) {
conditionalSchema.accept(new ConditionalSchemaValidatingVisitor(subject, this));
}

ValidationException getFailureOfSchema(Schema schema, Object input) {
Object origSubject = this.subject;
this.subject = input;
Expand Down
15 changes: 15 additions & 0 deletions core/src/main/java/org/everit/json/schema/Visitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -183,4 +183,19 @@ void visitMinLength(Integer minLength) {

void visitCombinedSchema(CombinedSchema combinedSchema) {
}

void visitConditionalSchema(ConditionalSchema conditionalSchema){
conditionalSchema.getIfSchema().ifPresent(this::visitIfSchema);
conditionalSchema.getThenSchema().ifPresent(this::visitThenSchema);
conditionalSchema.getElseSchema().ifPresent(this::visitElseSchema);
}

void visitIfSchema(Schema ifSchema) {
}

void visitThenSchema(Schema thenSchema) {
}

void visitElseSchema(Schema elseSchema) {
}
}
Loading