Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
dev.harrel.jsonschema.Applicators Maven / Gradle / Ivy
package dev.harrel.jsonschema;
import java.math.BigInteger;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import static java.util.Collections.*;
class PrefixItemsEvaluator implements Evaluator {
private final List prefixRefs;
PrefixItemsEvaluator(SchemaParsingContext ctx, JsonNode node) {
if (!node.isArray()) {
throw new IllegalArgumentException();
}
this.prefixRefs = unmodifiableList(node.asArray().stream()
.map(ctx::getCompoundUri)
.collect(Collectors.toList()));
}
@Override
public Result evaluate(EvaluationContext ctx, JsonNode node) {
if (!node.isArray()) {
return Result.success();
}
List elements = node.asArray();
int size = Math.min(prefixRefs.size(), elements.size());
boolean valid = true;
for (int i = 0; i < size; i++) {
valid = ctx.resolveInternalRefAndValidate(prefixRefs.get(i), elements.get(i)) && valid;
}
return valid ? Result.success(prefixRefs.size()) : Result.failure();
}
}
class ItemsEvaluator implements Evaluator {
private final CompoundUri schemaRef;
ItemsEvaluator(SchemaParsingContext ctx, JsonNode node) {
if (!node.isObject() && !node.isBoolean()) {
throw new IllegalArgumentException();
}
this.schemaRef = ctx.getCompoundUri(node);
}
@Override
public Result evaluate(EvaluationContext ctx, JsonNode node) {
if (!node.isArray()) {
return Result.success();
}
List array = node.asArray();
int prefixItemsSize = ctx.getSiblingAnnotation(Keyword.PREFIX_ITEMS, node.getJsonPointer(), Integer.class).orElse(0);
boolean valid = true;
for (int i = prefixItemsSize; i < array.size(); i++) {
valid = ctx.resolveInternalRefAndValidate(schemaRef, array.get(i)) && valid;
}
return valid ? Result.success(true) : Result.failure();
}
@Override
public int getOrder() {
return 10;
}
}
class ItemsLegacyEvaluator implements Evaluator {
private final CompoundUri schemaRef;
private final List schemaRefs;
ItemsLegacyEvaluator(SchemaParsingContext ctx, JsonNode node) {
if (node.isObject() || node.isBoolean()) {
this.schemaRef = ctx.getCompoundUri(node);
this.schemaRefs = null;
} else if (node.isArray()) {
this.schemaRef = null;
this.schemaRefs = unmodifiableList(node.asArray().stream()
.map(ctx::getCompoundUri)
.collect(Collectors.toList()));
} else {
throw new IllegalArgumentException();
}
}
@Override
public Result evaluate(EvaluationContext ctx, JsonNode node) {
if (!node.isArray()) {
return Result.success();
}
List array = node.asArray();
if (schemaRef != null) {
boolean valid = array.stream()
.filter(element -> ctx.resolveInternalRefAndValidate(schemaRef, element))
.count() == array.size();
return valid ? Result.success(true) : Result.failure();
} else {
int size = Math.min(schemaRefs.size(), array.size());
boolean valid = IntStream.range(0, size)
.boxed()
.filter(idx -> ctx.resolveInternalRefAndValidate(schemaRefs.get(idx), array.get(idx)))
.count() == size;
return valid ? Result.success(schemaRefs.size()) : Result.failure();
}
}
}
class AdditionalItemsEvaluator implements Evaluator {
private final CompoundUri schemaRef;
AdditionalItemsEvaluator(SchemaParsingContext ctx, JsonNode node) {
if (!node.isObject() && !node.isBoolean()) {
throw new IllegalArgumentException();
}
this.schemaRef = ctx.getCompoundUri(node);
}
@Override
public Result evaluate(EvaluationContext ctx, JsonNode node) {
if (!node.isArray()) {
return Result.success();
}
List array = node.asArray();
Optional itemsAnnotation = ctx.getSiblingAnnotation(Keyword.ITEMS, node.getJsonPointer());
boolean shouldSkip = itemsAnnotation.map(Boolean.class::isInstance).orElse(false);
if (shouldSkip) {
return Result.success(true);
}
int itemsSize = itemsAnnotation.filter(Integer.class::isInstance).map(Integer.class::cast).orElse(array.size());
int size = Math.max(array.size() - itemsSize, 0);
boolean valid = array.stream()
.skip(itemsSize)
.filter(element -> ctx.resolveInternalRefAndValidate(schemaRef, element))
.count() == size;
return valid ? Result.success(true) : Result.failure();
}
@Override
public int getOrder() {
return 10;
}
}
class ContainsEvaluator implements Evaluator {
private final CompoundUri schemaRef;
private final boolean minContainsZero;
ContainsEvaluator(SchemaParsingContext ctx, JsonNode node) {
if (!node.isObject() && !node.isBoolean()) {
throw new IllegalArgumentException();
}
this.schemaRef = ctx.getCompoundUri(node);
this.minContainsZero = Optional.ofNullable(ctx.getCurrentSchemaObject().get(Keyword.MIN_CONTAINS))
.map(JsonNode::asInteger)
.map(BigInteger::intValueExact)
.map(min -> min == 0)
.orElse(false);
}
@Override
public Result evaluate(EvaluationContext ctx, JsonNode node) {
if (!node.isArray()) {
return Result.success();
}
List array = node.asArray();
List indices = unmodifiableList(IntStream.range(0, array.size())
.filter(i -> ctx.resolveInternalRefAndValidate(schemaRef, array.get(i)))
.boxed()
.collect(Collectors.toList()));
return minContainsZero || !indices.isEmpty() ? Result.success(indices) : Result.failure("Array contains no matching items");
}
}
class AdditionalPropertiesEvaluator implements Evaluator {
private final CompoundUri schemaRef;
AdditionalPropertiesEvaluator(SchemaParsingContext ctx, JsonNode node) {
if (!node.isObject() && !node.isBoolean()) {
throw new IllegalArgumentException();
}
this.schemaRef = ctx.getCompoundUri(node);
}
@Override
public Result evaluate(EvaluationContext ctx, JsonNode node) {
if (!node.isObject()) {
return Result.success();
}
String instanceLocation = node.getJsonPointer();
Set props = new HashSet<>();
ctx.getSiblingAnnotation(Keyword.PROPERTIES, instanceLocation, Set.class).ifPresent(props::addAll);
ctx.getSiblingAnnotation(Keyword.PATTERN_PROPERTIES, instanceLocation, Set.class).ifPresent(props::addAll);
Map toBeProcessed = new HashMap<>(node.asObject());
toBeProcessed.keySet().removeAll(props);
boolean valid = true;
for (JsonNode propNode : toBeProcessed.values()) {
valid = ctx.resolveInternalRefAndValidate(schemaRef, propNode) && valid;
}
return valid ? Result.success(unmodifiableSet(toBeProcessed.keySet())) : Result.failure();
}
@Override
public int getOrder() {
return 10;
}
}
class PropertiesEvaluator implements Evaluator {
private final Map schemaRefs;
PropertiesEvaluator(SchemaParsingContext ctx, JsonNode node) {
if (!node.isObject()) {
throw new IllegalArgumentException();
}
Map uris = new HashMap<>();
for (Map.Entry entry : node.asObject().entrySet()) {
uris.put(entry.getKey(), ctx.getCompoundUri(entry.getValue()));
}
this.schemaRefs = unmodifiableMap(uris);
}
@Override
public Result evaluate(EvaluationContext ctx, JsonNode node) {
if (!node.isObject()) {
return Result.success();
}
Set processed = new HashSet<>();
boolean valid = true;
for (Map.Entry entry : node.asObject().entrySet()) {
CompoundUri ref = schemaRefs.get(entry.getKey());
if (ref != null) {
processed.add(entry.getKey());
valid = ctx.resolveInternalRefAndValidate(ref, entry.getValue()) && valid;
}
}
return valid ? Result.success(unmodifiableSet(processed)) : Result.failure();
}
}
class PatternPropertiesEvaluator implements Evaluator {
private final Map schemasByPatterns;
PatternPropertiesEvaluator(SchemaParsingContext ctx, JsonNode node) {
if (!node.isObject()) {
throw new IllegalArgumentException();
}
this.schemasByPatterns = node.asObject().entrySet().stream()
.collect(Collectors.toMap(e -> Pattern.compile(e.getKey()), e -> ctx.getCompoundUri(e.getValue())));
}
@Override
public Result evaluate(EvaluationContext ctx, JsonNode node) {
if (!node.isObject()) {
return Result.success();
}
boolean valid = true;
Set processed = new HashSet<>();
for (Map.Entry entry : node.asObject().entrySet()) {
for (Map.Entry patternEntry : schemasByPatterns.entrySet()) {
if (patternEntry.getKey().matcher(entry.getKey()).find()) {
processed.add(entry.getKey());
valid = ctx.resolveInternalRefAndValidate(patternEntry.getValue(), entry.getValue()) && valid;
}
}
}
return valid ? Result.success(unmodifiableSet(processed)) : Result.failure();
}
}
class DependentSchemasEvaluator implements Evaluator {
private final Map dependentSchemas;
DependentSchemasEvaluator(SchemaParsingContext ctx, JsonNode node) {
if (!node.isObject()) {
throw new IllegalArgumentException();
}
this.dependentSchemas = toMap(ctx, node.asObject());
}
public DependentSchemasEvaluator(SchemaParsingContext ctx, Map objectNode) {
this.dependentSchemas = toMap(ctx, objectNode);
}
@Override
public Result evaluate(EvaluationContext ctx, JsonNode node) {
if (!node.isObject()) {
return Result.success();
}
List failedFields = new ArrayList<>();
for (Map.Entry e : node.asObject().entrySet()) {
CompoundUri ref = dependentSchemas.get(e.getKey());
if (ref != null && !ctx.resolveInternalRefAndValidate(ref, node)) {
failedFields.add(e.getKey());
}
}
if (failedFields.isEmpty()) {
return Result.success();
} else {
return Result.failure(String.format("Object does not match dependent schemas for some properties %s", failedFields));
}
}
private static Map toMap(SchemaParsingContext ctx, Map objectNode) {
return objectNode.entrySet()
.stream()
.collect(Collectors.toMap(Map.Entry::getKey, e -> ctx.getCompoundUri(e.getValue())));
}
}
class PropertyNamesEvaluator implements Evaluator {
private final CompoundUri schemaRef;
PropertyNamesEvaluator(SchemaParsingContext ctx, JsonNode node) {
if (!node.isObject() && !node.isBoolean()) {
throw new IllegalArgumentException();
}
this.schemaRef = ctx.getCompoundUri(node);
}
@Override
public Result evaluate(EvaluationContext ctx, JsonNode node) {
if (!node.isObject()) {
return Result.success();
}
Map object = node.asObject();
boolean valid = object.keySet().stream()
.filter(propName -> ctx.resolveInternalRefAndValidate(schemaRef, new StringNode(propName, node.getJsonPointer())))
.count() == object.size();
return valid ? Result.success() : Result.failure();
}
}
class IfThenElseEvaluator implements Evaluator {
private final CompoundUri ifRef;
private final Optional thenRef;
private final Optional elseRef;
IfThenElseEvaluator(SchemaParsingContext ctx, JsonNode node) {
if (!node.isObject() && !node.isBoolean()) {
throw new IllegalArgumentException();
}
this.ifRef = ctx.getCompoundUri(node);
this.thenRef = Optional.ofNullable(ctx.getCurrentSchemaObject().get(Keyword.THEN))
.map(ctx::getCompoundUri);
this.elseRef = Optional.ofNullable(ctx.getCurrentSchemaObject().get(Keyword.ELSE))
.map(ctx::getCompoundUri);
}
@Override
public Result evaluate(EvaluationContext ctx, JsonNode node) {
if (ctx.resolveInternalRefAndValidate(ifRef, node)) {
boolean valid = thenRef
.map(ref -> ctx.resolveInternalRefAndValidate(ref, node))
.orElse(true);
return valid ? Result.success() : Result.failure("Value matches against schema from 'if' but does not match against schema from 'then'");
} else {
boolean valid = elseRef
.map(ref -> ctx.resolveInternalRefAndValidate(ref, node))
.orElse(true);
return valid ? Result.success() : Result.failure("Value does not match against schema from 'if' and 'else'");
}
}
}
class AllOfEvaluator implements Evaluator {
private final List refs;
AllOfEvaluator(SchemaParsingContext ctx, JsonNode node) {
if (!node.isArray()) {
throw new IllegalArgumentException();
}
this.refs = unmodifiableList(node.asArray().stream().map(ctx::getCompoundUri).collect(Collectors.toList()));
}
@Override
public Result evaluate(EvaluationContext ctx, JsonNode node) {
List unmatchedIndexes = new ArrayList<>();
for (int i = 0; i < refs.size(); i++) {
if (!ctx.resolveInternalRefAndValidate(refs.get(i), node)) {
unmatchedIndexes.add(i);
}
}
if (unmatchedIndexes.isEmpty()) {
return Result.success();
}
return Result.failure(String.format("Value does not match against the schemas at indexes %s", unmatchedIndexes));
}
}
class AnyOfEvaluator implements Evaluator {
private final List refs;
AnyOfEvaluator(SchemaParsingContext ctx, JsonNode node) {
if (!node.isArray()) {
throw new IllegalArgumentException();
}
this.refs = unmodifiableList(node.asArray().stream().map(ctx::getCompoundUri).collect(Collectors.toList()));
}
@Override
public Result evaluate(EvaluationContext ctx, JsonNode node) {
boolean valid = false;
for (CompoundUri ref : refs) {
valid = ctx.resolveInternalRefAndValidate(ref, node) || valid;
}
return valid ? Result.success() : Result.failure("Value does not match against any of the schemas");
}
}
class OneOfEvaluator implements Evaluator {
private final List refs;
OneOfEvaluator(SchemaParsingContext ctx, JsonNode node) {
if (!node.isArray()) {
throw new IllegalArgumentException();
}
this.refs = unmodifiableList(node.asArray().stream().map(ctx::getCompoundUri).collect(Collectors.toList()));
}
@Override
public Result evaluate(EvaluationContext ctx, JsonNode node) {
List matchedIndexes = new ArrayList<>();
for (int i = 0; i < refs.size(); i++) {
if (ctx.resolveInternalRefAndValidate(refs.get(i), node)) {
matchedIndexes.add(i);
}
}
if (matchedIndexes.size() == 1) {
return Result.success();
}
if (matchedIndexes.isEmpty()) {
return Result.failure("Value does not match against any of the schemas");
}
return Result.failure(String.format("Value matches against more than one schema. Matched schema indexes %s", matchedIndexes));
}
}
class NotEvaluator implements Evaluator {
private final CompoundUri schemaUri;
NotEvaluator(SchemaParsingContext ctx, JsonNode node) {
if (!node.isObject() && !node.isBoolean()) {
throw new IllegalArgumentException();
}
this.schemaUri = ctx.getCompoundUri(node);
}
@Override
public Result evaluate(EvaluationContext ctx, JsonNode node) {
boolean valid = !ctx.resolveInternalRefAndValidate(schemaUri, node);
return valid ? Result.success() : Result.failure("Value matches against given schema but it must not");
}
}
class UnevaluatedItemsEvaluator implements Evaluator {
private final CompoundUri schemaRef;
UnevaluatedItemsEvaluator(SchemaParsingContext ctx, JsonNode node) {
if (!node.isObject() && !node.isBoolean()) {
throw new IllegalArgumentException();
}
this.schemaRef = ctx.getCompoundUri(node);
}
@Override
public Result evaluate(EvaluationContext ctx, JsonNode node) {
if (!node.isArray()) {
return Result.success();
}
Set evaluatedInstances = ctx.calculateEvaluatedInstancesFromParent();
boolean valid = true;
for (JsonNode arrayNode : node.asArray()) {
if (!evaluatedInstances.contains(arrayNode.getJsonPointer())) {
valid = ctx.resolveInternalRefAndValidate(schemaRef, arrayNode) && valid;
}
}
return valid ? Result.success() : Result.failure();
}
@Override
public int getOrder() {
return 30;
}
}
class UnevaluatedPropertiesEvaluator implements Evaluator {
private final CompoundUri schemaRef;
UnevaluatedPropertiesEvaluator(SchemaParsingContext ctx, JsonNode node) {
if (!node.isObject() && !node.isBoolean()) {
throw new IllegalArgumentException();
}
this.schemaRef = ctx.getCompoundUri(node);
}
@Override
public Result evaluate(EvaluationContext ctx, JsonNode node) {
if (!node.isObject()) {
return Result.success();
}
Set evaluatedInstances = ctx.calculateEvaluatedInstancesFromParent();
boolean valid = true;
for (JsonNode fieldNode : node.asObject().values()) {
if (!evaluatedInstances.contains(fieldNode.getJsonPointer())) {
valid = ctx.resolveInternalRefAndValidate(schemaRef, fieldNode) && valid;
}
}
return valid ? Result.success() : Result.failure();
}
@Override
public int getOrder() {
return 20;
}
}
class RefEvaluator implements Evaluator {
private final CompoundUri ref;
RefEvaluator(JsonNode node) {
if (!node.isString()) {
throw new IllegalArgumentException();
}
this.ref = CompoundUri.fromString(node.asString());
}
@Override
public Result evaluate(EvaluationContext ctx, JsonNode node) {
try {
return ctx.resolveRefAndValidate(ref, node) ? Result.success() : Result.failure();
} catch (SchemaNotFoundException e) {
return Result.failure(String.format("Resolution of $ref [%s] failed", ref));
}
}
}
class DynamicRefEvaluator implements Evaluator {
private final CompoundUri ref;
DynamicRefEvaluator(JsonNode node) {
if (!node.isString()) {
throw new IllegalArgumentException();
}
this.ref = CompoundUri.fromString(node.asString());
}
@Override
public Result evaluate(EvaluationContext ctx, JsonNode node) {
try {
return ctx.resolveDynamicRefAndValidate(ref, node) ? Result.success() : Result.failure();
} catch (SchemaNotFoundException e) {
return Result.failure(String.format("Resolution of $dynamicRef [%s] failed", ref));
}
}
}
class RecursiveRefEvaluator implements Evaluator {
private final String ref;
RecursiveRefEvaluator(JsonNode node) {
if (!node.isString()) {
throw new IllegalArgumentException();
}
this.ref = node.asString();
}
@Override
public Result evaluate(EvaluationContext ctx, JsonNode node) {
try {
return ctx.resolveRecursiveRefAndValidate(ref, node) ? Result.success() : Result.failure();
} catch (SchemaNotFoundException e) {
return Result.failure(String.format("Resolution of $recursiveRef [%s] failed", ref));
}
}
}