diff --git a/core/src/main/java/org/everit/json/schema/AbstractCustomTypeSchema.java b/core/src/main/java/org/everit/json/schema/AbstractCustomTypeSchema.java new file mode 100644 index 000000000..eccb4141b --- /dev/null +++ b/core/src/main/java/org/everit/json/schema/AbstractCustomTypeSchema.java @@ -0,0 +1,36 @@ +package org.everit.json.schema; + +/** + * Superclass of all custom types + */ +public abstract class AbstractCustomTypeSchema extends Schema { + /** + * Constructor. + * + * @param builder + * the builder containing the optional title, description and id attributes of the schema + */ + protected AbstractCustomTypeSchema(Schema.Builder builder) { + super(builder); + } + + /** + * On custom types, it should return an instance of its own visitor implementation + * + * @param subject + * the subject/context of the new visitor + * + * @param owner + * the owner of the new visitor + * + * @return + * The newly created Visitor for this custom type + * + */ + public abstract Visitor buildVisitor(Object subject,ValidatingVisitor owner); + + @Override void accept(Visitor visitor) { + visitor.visitCustomTypeSchema(this); + } + +} \ No newline at end of file diff --git a/core/src/main/java/org/everit/json/schema/ValidatingVisitor.java b/core/src/main/java/org/everit/json/schema/ValidatingVisitor.java index 5b7b419df..1058ac311 100644 --- a/core/src/main/java/org/everit/json/schema/ValidatingVisitor.java +++ b/core/src/main/java/org/everit/json/schema/ValidatingVisitor.java @@ -148,6 +148,11 @@ void visitStringSchema(StringSchema stringSchema) { stringSchema.accept(new StringSchemaValidatingVisitor(subject, this)); } + @Override + void visitCustomTypeSchema(AbstractCustomTypeSchema customTypeSchema) { + customTypeSchema.accept(customTypeSchema.buildVisitor(subject, this)); + } + @Override void visitCombinedSchema(CombinedSchema combinedSchema) { Collection subschemas = combinedSchema.getSubschemas(); diff --git a/core/src/main/java/org/everit/json/schema/Visitor.java b/core/src/main/java/org/everit/json/schema/Visitor.java index 18d5d12a9..7aee6d2ae 100644 --- a/core/src/main/java/org/everit/json/schema/Visitor.java +++ b/core/src/main/java/org/everit/json/schema/Visitor.java @@ -170,6 +170,9 @@ void visitStringSchema(StringSchema stringSchema) { visitFormat(stringSchema.getFormatValidator()); } + void visitCustomTypeSchema(AbstractCustomTypeSchema customTypeSchema) { + } + void visitFormat(FormatValidator formatValidator) { } diff --git a/core/src/main/java/org/everit/json/schema/loader/LoaderConfig.java b/core/src/main/java/org/everit/json/schema/loader/LoaderConfig.java index dba904211..4875f9c62 100644 --- a/core/src/main/java/org/everit/json/schema/loader/LoaderConfig.java +++ b/core/src/main/java/org/everit/json/schema/loader/LoaderConfig.java @@ -6,8 +6,11 @@ import static org.everit.json.schema.loader.SpecificationVersion.DRAFT_6; import static org.everit.json.schema.loader.SpecificationVersion.DRAFT_7; +import java.lang.reflect.Method; + import java.net.URI; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.everit.json.schema.FormatValidator; @@ -27,6 +30,10 @@ static LoaderConfig defaultV4Config() { final SchemaClient schemaClient; final Map formatValidators; + + final Map customTypesMap; + + final Map> customTypesKeywordsMap; final Map schemasByURI; @@ -40,15 +47,19 @@ static LoaderConfig defaultV4Config() { LoaderConfig(SchemaClient schemaClient, Map formatValidators, SpecificationVersion specVersion, boolean useDefaults) { - this(schemaClient, formatValidators, emptyMap(), specVersion, useDefaults, false, new JavaUtilRegexpFactory()); + this(schemaClient, formatValidators, emptyMap(), specVersion, useDefaults, false, new JavaUtilRegexpFactory(), emptyMap(), emptyMap()); } LoaderConfig(SchemaClient schemaClient, Map formatValidators, Map schemasByURI, SpecificationVersion specVersion, boolean useDefaults, boolean nullableSupport, - RegexpFactory regexpFactory) { + RegexpFactory regexpFactory, + Map customTypesMap, + Map> customTypesKeywordsMap) { this.schemaClient = requireNonNull(schemaClient, "schemaClient cannot be null"); this.formatValidators = requireNonNull(formatValidators, "formatValidators cannot be null"); + this.customTypesMap = requireNonNull(customTypesMap, "customTypesMap cannot be null"); + this.customTypesKeywordsMap = requireNonNull(customTypesKeywordsMap, "customTypesKeywordsMap cannot be null"); if (schemasByURI == null) { this.schemasByURI = new HashMap<>(); } else { diff --git a/core/src/main/java/org/everit/json/schema/loader/SchemaExtractor.java b/core/src/main/java/org/everit/json/schema/loader/SchemaExtractor.java index 8bd604163..80e79f15b 100644 --- a/core/src/main/java/org/everit/json/schema/loader/SchemaExtractor.java +++ b/core/src/main/java/org/everit/json/schema/loader/SchemaExtractor.java @@ -9,13 +9,18 @@ import static org.everit.json.schema.loader.SpecificationVersion.DRAFT_4; import static org.everit.json.schema.loader.SpecificationVersion.DRAFT_7; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Set; +import org.everit.json.schema.AbstractCustomTypeSchema; import org.everit.json.schema.ArraySchema; import org.everit.json.schema.BooleanSchema; import org.everit.json.schema.CombinedSchema; @@ -95,7 +100,7 @@ abstract class AbstractSchemaExtractor implements SchemaExtractor { protected JsonObject schemaJson; - private KeyConsumer consumedKeys; + protected KeyConsumer consumedKeys; final SchemaLoader defaultLoader; @@ -235,9 +240,13 @@ private ConditionalSchema.Builder buildConditionalSchema() { } class TypeBasedSchemaExtractor extends AbstractSchemaExtractor { + private Map customTypesMap; + private Map> customTypesKeywordsMap; - TypeBasedSchemaExtractor(SchemaLoader defaultLoader) { + TypeBasedSchemaExtractor(SchemaLoader defaultLoader, Map customTypesMap, Map> customTypesKeywordsMap) { super(defaultLoader); + this.customTypesMap = customTypesMap; + this.customTypesKeywordsMap = customTypesKeywordsMap; } @Override List> extract() { @@ -276,7 +285,32 @@ private Schema.Builder loadForExplicitType(String typeString) { case "object": return buildObjectSchema(); default: - throw new SchemaException(schemaJson.ls.locationOfCurrentObj(), format("unknown type: [%s]", typeString)); + if(customTypesMap.containsKey(typeString)) { + // Calling the public static builder method using the + // Java reflection mechanisms + Method builderMethod = customTypesMap.get(typeString); + if(builderMethod==null) { + throw new SchemaException(schemaJson.ls.locationOfCurrentObj(), format("type: [%s] builder creation has failed, as type was not found", typeString)); + } + + List typeKeywords = customTypesKeywordsMap.get(typeString); + if(typeKeywords==null) { + throw new SchemaException(schemaJson.ls.locationOfCurrentObj(), format("type: [%s] builder creation has failed, as type was not found", typeString)); + } + try { + // Register the listened keywords + typeKeywords.forEach(consumedKeys::keyConsumed); + + // Now, obtain the schema loader + return (Schema.Builder) builderMethod.invoke(null,schemaJson.ls, config(), defaultLoader); + } catch(InvocationTargetException ite) { + throw new SchemaException(schemaJson.ls.locationOfCurrentObj(), format("type: [%s] builder creation has failed", typeString)); + } catch(IllegalAccessException iae) { + throw new SchemaException(schemaJson.ls.locationOfCurrentObj(), format("type: [%s] builder creation is not allowed", typeString)); + } + } else { + throw new SchemaException(schemaJson.ls.locationOfCurrentObj(), format("unknown type: [%s]", typeString)); + } } } diff --git a/core/src/main/java/org/everit/json/schema/loader/SchemaLoader.java b/core/src/main/java/org/everit/json/schema/loader/SchemaLoader.java index 505586514..b7ac39c5c 100644 --- a/core/src/main/java/org/everit/json/schema/loader/SchemaLoader.java +++ b/core/src/main/java/org/everit/json/schema/loader/SchemaLoader.java @@ -9,6 +9,10 @@ import static org.everit.json.schema.loader.SpecificationVersion.DRAFT_6; import static org.everit.json.schema.loader.SpecificationVersion.DRAFT_7; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + import java.net.URI; import java.net.URISyntaxException; import java.util.Collection; @@ -18,6 +22,7 @@ import java.util.Objects; import java.util.Optional; +import org.everit.json.schema.AbstractCustomTypeSchema; import org.everit.json.schema.CombinedSchema; import org.everit.json.schema.EmptySchema; import org.everit.json.schema.FalseSchema; @@ -69,13 +74,86 @@ public static class SchemaLoaderBuilder { private boolean nullableSupport = false; RegexpFactory regexpFactory = new JavaUtilRegexpFactory(); + + Map customTypesMap = new HashMap<>(); + Map> customTypesKeywordsMap = new HashMap<>(); Map schemasByURI = null; public SchemaLoaderBuilder() { setSpecVersion(DRAFT_4); } - + + /** + * Registers a custom schema type + * + * @param entry + * a Map.Entry with the typeName and the class to register + * @return {@code this} + */ + public SchemaLoaderBuilder addCustomType(Map.Entry> entry) { + return addCustomType(entry.getKey(),entry.getValue()); + } + + /** + * Registers a custom schema type + * + * @param typeName + * the type name to use for this custom JSON Schema type + * @param clazz + * the class which implements the validation of this custom JSON Schema type + * @return {@code this} + */ + public SchemaLoaderBuilder addCustomType(String typeName,Class clazz) { + typeName = requireNonNull(typeName, "the name of the custom type cannot be null"); + if(typeName.length() == 0) { + throw new IllegalArgumentException("the name of the custom type must be non-empty"); + } + + // Checking the pre-conditions + Method method = null; + try { + method = clazz.getMethod("schemaBuilderLoader", LoadingState.class, LoaderConfig.class, SchemaLoader.class); + int mods = method.getModifiers(); + if(!Modifier.isStatic(mods) || !Modifier.isPublic(mods)) { + throw new IllegalArgumentException("class '" + clazz.getName() + "', manager of custom type '" + typeName + "' must have a public static 'schemaBuilderLoader(LoadingState ls, LoaderConfig config, SchemaLoader defaultLoader)' method"); + } + Class retClazz = method.getReturnType(); + retClazz.asSubclass(Schema.Builder.class); + } catch(NoSuchMethodException nsme) { + throw new IllegalArgumentException("class '" + clazz.getName() + "', manager of custom type '" + typeName + "' must have a 'schemaBuilderLoader(LoadingState ls, LoaderConfig config, SchemaLoader defaultLoader)' method"); + } catch(ClassCastException cce) { + throw new IllegalArgumentException("class '" + clazz.getName() + "', manager of custom type '" + typeName + "': 'schemaBuilderLoader(LoadingState ls, LoaderConfig config, SchemaLoader defaultLoader)' method must return an instance of Schema.Builder"); + } + + List customTypeKeywords = null; + try { + Method kwMethod = clazz.getMethod("schemaKeywords"); + int mods = method.getModifiers(); + if(!Modifier.isStatic(mods) || !Modifier.isPublic(mods)) { + throw new IllegalArgumentException("class '" + clazz.getName() + "', manager of custom type '" + typeName + "' must have a public static 'schemaKeywords()' method"); + } + Class retClazz = kwMethod.getReturnType(); + retClazz.asSubclass(List.class); + + // Now, obtain the list + customTypeKeywords = (List)kwMethod.invoke(null); + } catch(NoSuchMethodException nsme) { + throw new IllegalArgumentException("class '" + clazz.getName() + "', manager of custom type '" + typeName + "' must have a 'schemaKeywords()' method"); + } catch(ClassCastException cce) { + throw new IllegalArgumentException("class '" + clazz.getName() + "', manager of custom type '" + typeName + "': 'schemaKeywords()' method must return an instance of List"); + } catch(InvocationTargetException ite) { + throw new IllegalArgumentException("class '" + clazz.getName() + "', manager of custom type '" + typeName + "' failed invoking 'schemaKeywords()' method"); + } catch(IllegalAccessException iae) { + throw new IllegalArgumentException("class '" + clazz.getName() + "', manager of custom type '" + typeName + "' failed invoking 'schemaKeywords()' method"); + } + + // If we are here, all is ok + customTypesMap.put(typeName,method); + customTypesKeywordsMap.put(typeName,customTypeKeywords); + return this; + } + /** * Registers a format validator with the name returned by {@link FormatValidator#formatName()}. * @@ -264,6 +342,19 @@ public static Schema load(final JSONObject schemaJson) { return SchemaLoader.load(schemaJson, new DefaultSchemaClient()); } + /** + * Creates Schema instance from its JSON representation. + * + * @param schemaJson + * the JSON representation of the schema. + * @param customTypes + * the custom types to use on the validation process + * @return the created schema + */ + public static Schema load(final JSONObject schemaJson, final Map> customTypes) { + return SchemaLoader.load(schemaJson, new DefaultSchemaClient(), customTypes); + } + /** * Creates Schema instance from its JSON representation. * @@ -274,8 +365,29 @@ public static Schema load(final JSONObject schemaJson) { * @return the created schema */ public static Schema load(final JSONObject schemaJson, final SchemaClient schemaClient) { - SchemaLoader loader = builder() - .schemaJson(schemaJson) + return SchemaLoader.load(schemaJson,schemaClient,null); + } + + /** + * Creates Schema instance from its JSON representation. + * + * @param schemaJson + * the JSON representation of the schema. + * @param schemaClient + * the HTTP client to be used for resolving remote JSON references. + * @param customTypes + * the custom types to use on the validation process + * @return the created schema + */ + public static Schema load(final JSONObject schemaJson, final SchemaClient schemaClient, final Map> customTypes) { + SchemaLoaderBuilder builder = builder(); + if(customTypes != null) { + for(Map.Entry> customTypeP: customTypes.entrySet()) { + builder.addCustomType(customTypeP); + } + } + + SchemaLoader loader = builder.schemaJson(schemaJson) .schemaClient(schemaClient) .build(); return loader.load().build(); @@ -320,7 +432,9 @@ public SchemaLoader(SchemaLoaderBuilder builder) { specVersion, builder.useDefaults, builder.nullableSupport, - builder.regexpFactory); + builder.regexpFactory, + builder.customTypesMap, + builder.customTypesKeywordsMap); this.ls = new LoadingState(config, builder.pointerSchemas, effectiveRootSchemaJson, @@ -389,7 +503,7 @@ private AdjacentSchemaExtractionState runSchemaExtractors(JsonObject o) { new CombinedSchemaLoader(this), new NotSchemaExtractor(this), new ConstSchemaExtractor(this), - new TypeBasedSchemaExtractor(this), + new TypeBasedSchemaExtractor(this,config.customTypesMap,config.customTypesKeywordsMap), new PropertySnifferSchemaExtractor(this) ); for (SchemaExtractor extractor : extractors) { diff --git a/tests/vanilla/src/main/java/org/everit/json/schema/CustomTestSchema.java b/tests/vanilla/src/main/java/org/everit/json/schema/CustomTestSchema.java new file mode 100644 index 000000000..e3e826556 --- /dev/null +++ b/tests/vanilla/src/main/java/org/everit/json/schema/CustomTestSchema.java @@ -0,0 +1,105 @@ +package org.everit.json.schema; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.List; + +import org.apache.commons.io.IOUtils; +import org.everit.json.schema.Schema; +import org.json.JSONObject; +import org.json.JSONTokener; +import org.junit.Test; + + +import static java.util.Objects.requireNonNull; +import static org.everit.json.schema.FormatValidator.NONE; + +import java.util.Objects; + +import org.everit.json.schema.internal.JSONPrinter; +import org.everit.json.schema.regexp.JavaUtilRegexpFactory; +import org.everit.json.schema.regexp.Regexp; + +/** + * @author jmfernandez + * {@code String} schema validator. + */ +public class CustomTestSchema extends AbstractCustomTypeSchema { + + /** + * Builder class for {@link CustomTestSchema}. + */ + public static class Builder extends Schema.Builder { + + private String rightValue; + + @Override + public CustomTestSchema build() { + return new CustomTestSchema(this); + } + + public Builder rightValue(final String rightValue) { + this.rightValue = rightValue; + return this; + } + } + + public static Builder builder() { + return new Builder(); + } + + private final String rightValue; + + public CustomTestSchema() { + this(builder()); + } + + /** + * Constructor. + * + * @param builder + * the builder object containing validation criteria + */ + public CustomTestSchema(final Builder builder) { + super(builder); + this.rightValue = builder.rightValue; + } + + @Override + public Visitor buildVisitor(Object subject,ValidatingVisitor owner) { + return new CustomTypeSchemaValidatingVisitor(subject, owner); + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o instanceof CustomTestSchema) { + CustomTestSchema that = (CustomTestSchema) o; + return that.canEqual(this) && + Objects.equals(rightValue, that.rightValue) && + super.equals(that); + } else { + return false; + } + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), rightValue); + } + + @Override + protected boolean canEqual(Object other) { + return other instanceof CustomTestSchema; + } + + @Override + void describePropertiesTo(JSONPrinter writer) { + writer.ifPresent("rightValue", rightValue); + } + + public String rightValue() { + return rightValue; + } +} diff --git a/tests/vanilla/src/main/java/org/everit/json/schema/CustomTypeSchemaValidatingVisitor.java b/tests/vanilla/src/main/java/org/everit/json/schema/CustomTypeSchemaValidatingVisitor.java new file mode 100644 index 000000000..8f0dedd2e --- /dev/null +++ b/tests/vanilla/src/main/java/org/everit/json/schema/CustomTypeSchemaValidatingVisitor.java @@ -0,0 +1,39 @@ +package org.everit.json.schema; + +import static java.lang.String.format; +import static java.util.Objects.requireNonNull; + +import java.util.Optional; + +import org.everit.json.schema.regexp.Regexp; + +public class CustomTypeSchemaValidatingVisitor extends Visitor { + + private final Object subject; + + private final ValidatingVisitor owner; + + private CustomTestSchema customTestSchema; + + private String rightValueSubject; + + public CustomTypeSchemaValidatingVisitor(Object subject, ValidatingVisitor owner) { + this.subject = subject; + this.owner = requireNonNull(owner, "failureReporter cannot be null"); + } + + void visitCustomTypeSchema(AbstractCustomTypeSchema customTestSchema) { + this.customTestSchema = (CustomTestSchema)customTestSchema; + if (owner.passesTypeCheck(String.class, true, false)) { + rightValueSubject = (String) subject; + visitRightValue(this.customTestSchema.rightValue()); + } + } + + void visitRightValue(String rightValue) { + if(rightValue != null && !rightValueSubject.equals(rightValue)) { + ValidationException violation = new ValidationException(customTestSchema,"'"+rightValueSubject+"' is not the right value ('"+rightValue+"')"); + owner.failure(violation); + } + } +} diff --git a/tests/vanilla/src/main/java/org/everit/json/schema/CustomTypeTest.java b/tests/vanilla/src/main/java/org/everit/json/schema/CustomTypeTest.java new file mode 100644 index 000000000..eeb30efe3 --- /dev/null +++ b/tests/vanilla/src/main/java/org/everit/json/schema/CustomTypeTest.java @@ -0,0 +1,70 @@ +package org.everit.json.schema; + +import java.io.IOException; +import java.io.InputStreamReader; + +import org.apache.commons.io.IOUtils; +import org.everit.json.schema.loader.CustomTestSchemaLoader; +import org.everit.json.schema.loader.SchemaLoader; +import org.everit.json.schema.Schema; +import org.everit.json.schema.ValidationException; +import org.json.JSONObject; +import org.json.JSONTokener; +import org.junit.Test; + + +import static java.util.Objects.requireNonNull; +import static org.everit.json.schema.FormatValidator.NONE; + +import java.util.Objects; +import java.util.HashMap; + +import org.everit.json.schema.internal.JSONPrinter; +import org.everit.json.schema.regexp.JavaUtilRegexpFactory; +import org.everit.json.schema.regexp.Regexp; + +public class CustomTypeTest { + + @Test + public void validateCustomType() throws IOException { + + JSONObject jsonSchema = new JSONObject(new JSONTokener( + IOUtils.toString( + new InputStreamReader(getClass().getResourceAsStream("/org/everit/json/schema/customType/schema.json"))) + )); + + JSONObject worksJson = new JSONObject(new JSONTokener( + IOUtils.toString( + new InputStreamReader(getClass().getResourceAsStream("/org/everit/json/schema/customType/works.json"))) + )); + + // An easy way to register the custom types + HashMap> customTypes = new HashMap<>(); + customTypes.put("customType",CustomTestSchemaLoader.class); + Schema schema = SchemaLoader.load(jsonSchema,customTypes); + + schema.validate(worksJson); + } + + + @Test(expected = ValidationException.class) + public void dontValidateCustomType() throws IOException { + + JSONObject jsonSchema = new JSONObject(new JSONTokener( + IOUtils.toString( + new InputStreamReader(getClass().getResourceAsStream("/org/everit/json/schema/customType/schema.json"))) + )); + + JSONObject failsJson = new JSONObject(new JSONTokener( + IOUtils.toString( + new InputStreamReader(getClass().getResourceAsStream("/org/everit/json/schema/customType/fails.json"))) + )); + + // An easy way to register the custom types + HashMap> customTypes = new HashMap<>(); + customTypes.put("customType",CustomTestSchemaLoader.class); + Schema schema = SchemaLoader.load(jsonSchema,customTypes); + + schema.validate(failsJson); + } +} diff --git a/tests/vanilla/src/main/java/org/everit/json/schema/loader/CustomTestSchemaLoader.java b/tests/vanilla/src/main/java/org/everit/json/schema/loader/CustomTestSchemaLoader.java new file mode 100644 index 000000000..47e66bbeb --- /dev/null +++ b/tests/vanilla/src/main/java/org/everit/json/schema/loader/CustomTestSchemaLoader.java @@ -0,0 +1,43 @@ +package org.everit.json.schema.loader; + +import static java.util.Arrays.asList; +import static java.util.Objects.requireNonNull; + +import java.util.List; + +import org.everit.json.schema.CustomTestSchema; +import org.everit.json.schema.Schema; + +/** + * @author jmfernandez + */ +public class CustomTestSchemaLoader { + static final List SCHEMA_PROPS = asList("rightValue"); + + private final LoadingState ls; + + private final LoaderConfig config; + + private final SchemaLoader defaultLoader; + + public CustomTestSchemaLoader(LoadingState ls, LoaderConfig config, SchemaLoader defaultLoader) { + this.ls = requireNonNull(ls, "ls cannot be null"); + this.config = requireNonNull(config, "config cannot be null"); + this.defaultLoader = requireNonNull(defaultLoader, "defaultLoader cannot be null"); + } + + CustomTestSchema.Builder load() { + CustomTestSchema.Builder builder = CustomTestSchema.builder(); + ls.schemaJson().maybe("rightValue").map(JsonValue::requireString).ifPresent(builder::rightValue); + return builder; + } + + // This method is + public static CustomTestSchema.Builder schemaBuilderLoader(LoadingState ls, LoaderConfig config, SchemaLoader schemaLoader) { + return new CustomTestSchemaLoader(ls, config, schemaLoader).load(); + } + + public static final List schemaKeywords() { + return CustomTestSchemaLoader.SCHEMA_PROPS; + } +} diff --git a/tests/vanilla/src/main/resources/org/everit/json/schema/customType/fails.json b/tests/vanilla/src/main/resources/org/everit/json/schema/customType/fails.json new file mode 100644 index 000000000..c16913a18 --- /dev/null +++ b/tests/vanilla/src/main/resources/org/everit/json/schema/customType/fails.json @@ -0,0 +1,3 @@ +{ + "custom": "fortytwo" +} diff --git a/tests/vanilla/src/main/resources/org/everit/json/schema/customType/schema.json b/tests/vanilla/src/main/resources/org/everit/json/schema/customType/schema.json new file mode 100644 index 000000000..7032b14ac --- /dev/null +++ b/tests/vanilla/src/main/resources/org/everit/json/schema/customType/schema.json @@ -0,0 +1,10 @@ +{ + "title": "Schema with a custom type", + "type": "object", + "properties": { + "custom": { + "type": "customType", + "rightValue": "42" + } + } +} diff --git a/tests/vanilla/src/main/resources/org/everit/json/schema/customType/works.json b/tests/vanilla/src/main/resources/org/everit/json/schema/customType/works.json new file mode 100644 index 000000000..cec9ff22b --- /dev/null +++ b/tests/vanilla/src/main/resources/org/everit/json/schema/customType/works.json @@ -0,0 +1,3 @@ +{ + "custom": "42" +}