diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ee12093 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/target +.idea +JsonSchema.iml diff --git a/example/example1/objectArrayInObject.json b/example/example1/objectArrayInObject.json new file mode 100644 index 0000000..c4ff533 --- /dev/null +++ b/example/example1/objectArrayInObject.json @@ -0,0 +1,8 @@ +{ + "name": "john", + "age": 30, + "hobbies": [ + { "name" : "soccer", "howFreq": 10 }, + { "name" : "swimming", "howFreq": 1} + ] +} \ No newline at end of file diff --git a/example/example1/objectArrayInObject_schema1.json b/example/example1/objectArrayInObject_schema1.json new file mode 100644 index 0000000..06d07ba --- /dev/null +++ b/example/example1/objectArrayInObject_schema1.json @@ -0,0 +1,22 @@ +[ + { + "type": "array", + "namespace": "hobby", + "name": "arr", + "doc": "simple sub array", + "fields": [ + {"name": "name", "type": "String"}, + {"name": "howFreq", "type": "Integer"} + ] + }, + { + "type": "object", + "namespace": "simple", + "name": "test", + "fields": [ + {"name": "name", "type": "String"}, + {"name": "age", "type": "Integer"}, + {"name": "hobbies", "type": "hobby.arr"} + ] + } +] \ No newline at end of file diff --git a/example/example1/objectArrayInObject_schema2.json b/example/example1/objectArrayInObject_schema2.json new file mode 100644 index 0000000..b9fc985 --- /dev/null +++ b/example/example1/objectArrayInObject_schema2.json @@ -0,0 +1,22 @@ +[ + { + "type": "object", + "namespace": "hobby", + "name": "obj", + "doc": "simple", + "fields": [ + {"name": "name", "type": "String"}, + {"name": "howFreq", "type": "Integer"} + ] + }, + { + "type": "object", + "namespace": "simple", + "name": "test", + "fields": [ + {"name": "name", "type": "String"}, + {"name": "age", "type": "Integer"}, + {"name": "hobbies", "type": "hobby.obj[]"} + ] + } +] \ No newline at end of file diff --git a/example/example2/arraysInsideObject.json b/example/example2/arraysInsideObject.json new file mode 100644 index 0000000..8ba29a9 --- /dev/null +++ b/example/example2/arraysInsideObject.json @@ -0,0 +1,4 @@ +{ + "subject": ["math", "english", "french"], + "score": [20, 24, 30] +} \ No newline at end of file diff --git a/example/example2/arraysInsideObject_schema.json b/example/example2/arraysInsideObject_schema.json new file mode 100644 index 0000000..55d5a50 --- /dev/null +++ b/example/example2/arraysInsideObject_schema.json @@ -0,0 +1,12 @@ +[ + { + "type": "object", + "namespace": "simple", + "name": "test2", + "doc": "simple", + "fields": [ + {"name": "subject", "type": "String[]"}, + {"name": "score", "type": "Integer[]"} + ] + } +] \ No newline at end of file diff --git a/example/example3/simpleObjectInArray.json b/example/example3/simpleObjectInArray.json new file mode 100644 index 0000000..5907aa5 --- /dev/null +++ b/example/example3/simpleObjectInArray.json @@ -0,0 +1,5 @@ +[ + {"subject": "math", "score": 80.2 }, + {"subject": "english", "score": 10.2 }, + {"subject": "french", "score": 20.2 } +] \ No newline at end of file diff --git a/example/example3/simpleObjectInArray_schema.json b/example/example3/simpleObjectInArray_schema.json new file mode 100644 index 0000000..1d92246 --- /dev/null +++ b/example/example3/simpleObjectInArray_schema.json @@ -0,0 +1,12 @@ +[ + { + "type": "array", + "namespace": "simple", + "name": "test3", + "doc": "simple", + "fields": [ + {"name": "subject", "type": "String"}, + {"name": "score", "type": "Double"} + ] + } +] \ No newline at end of file diff --git a/example/example4/usingRegex.json b/example/example4/usingRegex.json new file mode 100644 index 0000000..6384d12 --- /dev/null +++ b/example/example4/usingRegex.json @@ -0,0 +1,4 @@ +{ + "/applicant-details/applicant-1/address-history" : "init", + "/applicant-details/applicant-2/address-history" : "deleted" +} \ No newline at end of file diff --git a/example/example4/usingRegex_schema.json b/example/example4/usingRegex_schema.json new file mode 100644 index 0000000..6af567e --- /dev/null +++ b/example/example4/usingRegex_schema.json @@ -0,0 +1,13 @@ +[ + { + "type": "object", + "namespace": "simple", + "name": "test4", + "doc": "validation schema", + "fields" : [ + { "name": "$REGEX$\\/applicant-details\\/applicant-([0-9])+\\/address-history", "type": "String" } + ] + } +] + + diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..83c1499 --- /dev/null +++ b/pom.xml @@ -0,0 +1,46 @@ + + + 4.0.0 + + com.github.sijoonlee + JsonSchemaValidator + 1.0-SNAPSHOT + + + + com.google.code.gson + gson + 2.8.5 + + + + org.slf4j + slf4j-simple + 1.7.30 + + + + junit + junit + 4.12 + test + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.7.0 + + 1.8 + 1.8 + + + + + \ No newline at end of file diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..04376d5 --- /dev/null +++ b/readme.md @@ -0,0 +1,185 @@ +## Simple JSON Schema and its Validator +- How I structured JSON schema is affected by [Apache Avro Schema](https://avro.apache.org/) + - Not exactly same, though +- There is an existing draft of [JSON schema](https://tools.ietf.org/html/draft-zyp-json-schema-04) + - But, in my opinion, this is far from easy-to-use + +## if you want to see examples first +- Please see **example** folder and **test** folder + +## Terminology +- There are two basic structures of Json + - One is **object**, which is wrapped by { } + - The other is **array**, which is wrapped by [ ] +- Json object can have zero or more **fields** +- Each field has **name** and **value** +- Below example has one field, of which "name" is "person" and "value" is "john" + ``` + { + "person": "john" + } + ``` + +### How to write Schema +- Schema is written as Json of which root element should be 'array' +- It is because Schema Json file can contain multiple set of Schema +- Each Schema set is called **Schema Record** + + ``` + [ // root is always array + { }, // one schema set, which I call 'record' + { } // second schema record + ] + ``` + +- The schema record has fields: 'type', 'namespace', 'name', 'fields' + ``` + [ + { + "type" : "object" + "namespace" : "schema.omp" + "name": "lead" + "fields" : [ + { "name": "age", "type": "Integer" }, + { "name": "job", "type": "String" } + ] + }, + { + // another schema record + } + + ] + ``` + - 'type' : it is either 'object' or 'array' + - 'namespace' : it is to avoid naming conflicts (ex) schema.omp + - 'name' : name of the schema (ex) lead + - note that full name of schema record is referred as [namespace].[name] + - full name example: schema.omp.lead + - 'fields' contains the information of fields inside Json obejct or Json array + - each field consists of field "name" and field "type" + - for example, { "name" : "age", "type" : "Integer" } + - 7 types exist for type-checking + - 6 types coming from Java data types + - String, Integer, BigInteger, Double, Boolean, OffsetDateTime + - Type-checking is simply to ensure the value can be parsed with that type + - for example, if value is "10.2", it can't be pared as Integer + - 1 more type for passing around the type-checking process + - TypeCheckingPass + - You can define customized types (see below section) + - A customized type is a schema record + - To use customized type, use full name of it as "type" + - for example, if schema record's full name is schema.person + ``` + { "name" : "person", "type" : "schema.person" } + ``` +### Json Example +- This example's root structure is "object" not "array" since the outer-most wrapping is done by { and } +- This example contains 3 fields: name, age, hobbies +- The fields 'hobbies' has an array of objects as its value + ``` + { + "name": "john", + "age": 30, + "hobbies": [ + { "name" : "soccer", "howFreq": 10 }, + { "name" : "swimming", "howFreq": 1} + ] + } + ``` + +### Writing Schema for the Example Json - 1 + +``` +[ + { + "type": "object", // this is referring to the root structure, which always is either 'object' or 'array' + "namespace": "simple", + "name": "object", + "fields": [ + {"name": "name", "type": "String"}, // There are 6 types supported: String, Integer, BigInteger, Double, Boolean, OffsetDateTime + {"name": "age", "type": "Integer"}, + {"name": "hobbies", "type": "hobby.array"} // This is Customized type, "hobby.array" refers to the full name of the other schema record + ] + }, + { + "type": "array", // this is referring to the array of objects (hobbies field) + "namespace": "hobby", + "name": "array", // full name is "hobby.array" + "doc": "simple sub array", + "fields": [ + {"name": "name", "type": "String"}, + {"name": "howFreq", "type": "Integer"} + ] + } +] +``` + +### Writing Schema for the Example Json - 2 +- This does the same thing as the previous example +``` +[ + { + "type": "object", + "namespace": "simple", + "name": "test", + "fields": [ + {"name": "name", "type": "String"}, + {"name": "age", "type": "Integer"}, + {"name": "hobbies", "type": "hobby.object[]"} // It is possible to make an array from an object by attaching [] at the end of the full name + ] + }, + { + "type": "object", // note that it is 'object' + "namespace": "hobby", + "name": "object", // full name is 'hobby.object' + "doc": "simple", + "fields": [ + {"name": "name", "type": "String"}, + {"name": "howFreq", "type": "Integer"} + ] + } +] +``` + +- please note that it's possible to use String[], Integer[] and so on + +## You can use Regex pattern for field name +- use prefix "$REGEX$" +- use escape characters where they are needed +- example + ``` + [ + { + "type": "object", + "namespace": "simple", + "name": "test", + "fields": [ + {"name": "$REGEX$\\/applicant-details\\/applicant-([0-9])+\\/address-history", "type": "String"} + ] + } + } + ``` + - if the field name is "/applicant-details/applicant-2/address-history", it is valid + +## How to use Schema Classes +1. Instantiate validator with schema json file +- example + ``` + SchemaValidator schemaValidator = new SchemaValidator("testData/schema/salesforceSchema.json"); + ``` +2. Run validator with JsonElement (gson class) + ``` + JsonElement json = [some process] + boolean isValid = schemaValidator.runWithJsonElement(json, "simple.test"); // the second argument 'simple.test' is the full name of the schema record of root element + ``` +3. or Run validator with Json file + ``` + boolean isValid = schemaValidator.runWithJsonFile("example/simpleStructure.json", "simple.test"); + + ``` + +## TODO +- There is no Regex checking for 'value' +- There is no required field checking + - Currently, error occurs only when it finds a field not listed in schema + - Therefore, it doesn't make an error when some fields in schema are missing \ No newline at end of file diff --git a/src/main/java/com/github/sijoonlee/SchemaRecord.java b/src/main/java/com/github/sijoonlee/SchemaRecord.java new file mode 100644 index 0000000..d81bb6d --- /dev/null +++ b/src/main/java/com/github/sijoonlee/SchemaRecord.java @@ -0,0 +1,117 @@ +package com.github.sijoonlee; + +import java.util.*; + +/* Gson will populate data into this class from Schema json file + * Please refer SchemaValiadator's constructor + */ +public class SchemaRecord { + + private String type; + private String namespace; + private String name; + private String doc; + private ArrayList fields; + + class SchemaField { + private String name; + private String type; + private String doc; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getDoc() { + return doc; + } + + public void setDoc(String doc) { + this.doc = doc; + } + } + + @Override + public String toString() { + return namespace + "." + name + ": " + doc; + } + + public String getName(){ + return name; + } + public String getNamespace(){ + return namespace; + } + public String getFullNamePath(){ + return namespace + "." + name; + } + public String getDoc() { + return doc; + } + public ArrayList getFields() { + return fields; + } + + public Set getFieldNames() { + Set names = new HashSet<>(); + for(SchemaField field: fields) { + names.add(field.name); + } + return names; + } + + public String getType(){ + return type; + } + + public String getFieldType(String name) { + String type = ""; + for(SchemaField field: fields) { + if( name.equals(field.name) ) { + type = field.type; + break; + } + } + return type; + } + + public Map getFieldProperties() { + Map entries = new HashMap<>(); + for(SchemaField field: fields){ + entries.put(field.name, field.type); + } + return entries; + } + + public String findFieldTypeFromFieldName(String name) { + final String REGEX_PREFIX = "$REGEX$"; + String type = null; + String pattern = ""; + for(SchemaField field: fields){ + if(field.name.equals(name)){ + type = field.type; + break; + } else if(field.name.startsWith(REGEX_PREFIX)){ + pattern = field.name.substring(REGEX_PREFIX.length()); + if(name.matches(pattern)){ + type = field.type; + break; + } + } + } + return type; + } + +} diff --git a/src/main/java/com/github/sijoonlee/SchemaValidator.java b/src/main/java/com/github/sijoonlee/SchemaValidator.java new file mode 100644 index 0000000..85eaf46 --- /dev/null +++ b/src/main/java/com/github/sijoonlee/SchemaValidator.java @@ -0,0 +1,299 @@ +package com.github.sijoonlee; + +import com.github.sijoonlee.util.JsonUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.github.sijoonlee.util.JsonUtil; + +import java.math.BigInteger; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.Map.Entry; + +public class SchemaValidator { + private final ArrayList schemas; + private final ArrayList recordNamedTypes; + private final ArrayList recordNamedArrayTypes; + private final ArrayList javaTypes; + private final ArrayList javaArrayTypes; + private static final Logger log = LoggerFactory.getLogger(SchemaValidator.class.getName()); + private final String FIELD_NAME_NOT_EXIST = "FIELD_NAME_NOT_EXIST"; + private final String TYPE_STRING = "String"; + private final String TYPE_INTEGER = "Integer"; + private final String TYPE_DOUBLE = "Double"; + private final String TYPE_BIGINTEGER = "BigInteger"; + private final String TYPE_BOOLEAN = "Boolean"; + private final String TYPE_OFFSETDATETIME = "OffsetDateTime"; + private final String TYPE_CHECKING_PASS = "TypeCheckingPass"; + + /* + @FirstParam: the path of Schema json file + */ + public SchemaValidator(String schemaPath) { + + // import schemas + schemas = new ArrayList<>(); + JsonArray jsonArray = JsonUtil.convertJsonFileToJsonArray(schemaPath); // this is because Schema's root element is always Json array + Gson gson = new Gson(); + for (JsonElement elm : jsonArray) { + // convert each item in array into SchemaRecord instance and push it to ArrayList + schemas.add(gson.fromJson(elm, SchemaRecord.class)); + } + + // Collect schema record's full names (ex: schema.omp.lead ) + // these full names can be referred as customized types + recordNamedTypes = getSchemaRecordNames(schemas); + + // init supported Java types + javaTypes = new ArrayList<>(); + javaTypes.add(TYPE_STRING); + javaTypes.add(TYPE_INTEGER); + javaTypes.add(TYPE_BIGINTEGER); + javaTypes.add(TYPE_DOUBLE); + javaTypes.add(TYPE_BOOLEAN); + javaTypes.add(TYPE_OFFSETDATETIME); + + // init array types derived from Java types (ex: String[] ) + javaArrayTypes = new ArrayList<>(); + for(String type : javaTypes){ + javaArrayTypes.add(type + "[]"); + } + + // init array types derived from customized types (ex: schema.omp.lead[] ) + recordNamedArrayTypes = new ArrayList<>(); + for(String type: recordNamedTypes){ + recordNamedArrayTypes.add(type + "[]"); + } + + } + + + private void parsingTest(String type, String value) throws Exception { + if (type.equals(TYPE_INTEGER)) { + try { + Integer.parseInt(value); + } catch (Exception ex) { + throw new Exception( "Field Type Error: can't be Integer - " + value); + } + } else if (type.equals(TYPE_BIGINTEGER)) { + try { + Long longValue = Long.parseLong(value); + BigInteger.valueOf(longValue); + } catch (Exception ex) { + throw new Exception( "Field Type Error: can't be BigInteger - " + value); + } + } else if (type.equals(TYPE_DOUBLE)) { + try { + Double.parseDouble(value); + } catch (Exception ex) { + throw new Exception( "Field Type Error: can't be Double - " + value); + } + } else if (type.equals(TYPE_BOOLEAN)) { + try { + Boolean.parseBoolean(value); + } catch (Exception ex) { + throw new Exception( "Field Type Error: can't be Boolean - " + value); + } + } else if (type.equals(TYPE_OFFSETDATETIME)) { + try { + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME; + OffsetDateTime.parse(value, dateTimeFormatter); + } catch (Exception ex) { + throw new Exception( "Field Type Error: can't be OffsetDateTime - " + value); + } + } + + } + + private ArrayList getSchemaRecordNames(ArrayList schemas) { + ArrayList names = new ArrayList<>(); + for (SchemaRecord schema : schemas) { + names.add(schema.getFullNamePath()); + } + return names; + } + private class FieldInfo { + public String type ; + public String name; + public JsonElement value; + + public FieldInfo(String type, String name, JsonElement value) { + this.type = type; + this.name = name; + this.value = value; + } + } + + private String getFieldType(int indexOfSchema, String name) throws Exception { + String type; + type = schemas.get(indexOfSchema).findFieldTypeFromFieldName(name); + if(type == null) { + throw new Exception("Field Name Error: can't find the field name in schema - " + name); + } + return type; + } + + private void putFieldIntoStack(Deque stack, Set> entries, int indexOfSchema) { + for (Entry entry : entries){ + String type = FIELD_NAME_NOT_EXIST; + try{ + type = getFieldType(indexOfSchema, entry.getKey()); + } catch (Exception ex) { + log.error("putFieldIntoStack"); + log.error(ex.getMessage()); + } + stack.push(new FieldInfo(type, entry.getKey(), entry.getValue())); + } + } + + /* + @FirstParam: it is the path of json file to be validated + @SecondParam: it is the full name of the schema record, which is specified inside of Schema json file + */ + public boolean runWithJsonFile(String targetJsonFilePath, String mainSchemaName){ + JsonElement targetJson; + int indexOfSchema = recordNamedTypes.indexOf(mainSchemaName); + if(indexOfSchema < 0) { + log.error("Main schema record's full name was wrong"); + return false; + } + if(schemas.get(indexOfSchema).getType().equals("array")){ + targetJson = JsonUtil.convertJsonFileToJsonArray(targetJsonFilePath); + } else if (schemas.get(indexOfSchema).getType().equals("object")) { + targetJson = JsonUtil.convertJsonFileToJsonObject(targetJsonFilePath); + } else { + log.error("record type should be 'array' or 'object'"); + return false; + } + return runWithJsonElement(targetJson, mainSchemaName); + } + + /* + @FirstParam: it is Gson's JsonElement object to be validated + @SecondParam: it is the full name of the schema record, which is specified inside of Schema json file + */ + public boolean runWithJsonElement(JsonElement targetJsonElement, String mainSchemaName) { + boolean isValid = true; + int fieldCounter = 0; + + // prepare + int indexOfSchema = recordNamedTypes.indexOf(mainSchemaName); + if(indexOfSchema < 0) { + log.error("Main schema name was wrong"); + return false; + } + Deque stack = new ArrayDeque<>(); + Set> entries; // + FieldInfo field; + + // Generating Initial Stack + // - check if it is json object or json array + // - if is array, unfold array and put all items into stack + // - if is object, put all items into stack + if(schemas.get(indexOfSchema).getType().equals("array")) { + + JsonArray targetJson = targetJsonElement.getAsJsonArray(); + for(JsonElement arrayItem : targetJson){ + entries = arrayItem.getAsJsonObject().entrySet(); + putFieldIntoStack(stack, entries, indexOfSchema); + } + } else if (schemas.get(indexOfSchema).getType().equals("object")) { + + JsonObject targetJson = targetJsonElement.getAsJsonObject(); + entries = targetJson.getAsJsonObject().entrySet(); + putFieldIntoStack(stack, entries, indexOfSchema); + } else { + log.error("record type should be 'array' or 'object'"); + return false; + } + + // pop a field from stack and validate it + while (stack.size() > 0) { + field = stack.pop(); + if (javaTypes.contains(field.type)) { + // System.out.println(field.name); + fieldCounter += 1; + try { + parsingTest(field.type, field.value.getAsString()); + } catch (Exception ex){ + isValid = false; + log.error(ex.getMessage() + " - " + field.name); + }; + + } else if (javaArrayTypes.contains(field.type)) { + // System.out.println(field.name); + fieldCounter += 1; + for(JsonElement arrayItem :field.value.getAsJsonArray()){ + try{ + // field.type looks like "String[]" + // field.type.substring(0, field.type.length()-2) is to delete "[]" + parsingTest(field.type.substring(0, field.type.length()-2), arrayItem.getAsString()); + } catch (Exception ex){ + isValid = false; + log.error(ex.getMessage() + " - " + field.name); + } + } + + } else if (recordNamedTypes.contains(field.type)) { + // System.out.println(field.name); + fieldCounter += 1; + indexOfSchema = recordNamedTypes.indexOf(field.type); + if(schemas.get(indexOfSchema).getType().equals("array")){ + JsonArray targetJson = field.value.getAsJsonArray(); + for(JsonElement arrayItem : targetJson){ + entries = arrayItem.getAsJsonObject().entrySet(); + putFieldIntoStack(stack, entries, indexOfSchema); + } + } else if (schemas.get(indexOfSchema).getType().equals("object")){ + entries = field.value.getAsJsonObject().entrySet(); + putFieldIntoStack(stack, entries, indexOfSchema); + } else { + log.error("record type should be 'array' or 'object'"); + return false; + } + } else if (recordNamedArrayTypes.contains(field.type)) { + // System.out.println(field.name); + fieldCounter += 1; + indexOfSchema = recordNamedTypes.indexOf(field.type.substring(0, field.type.length()-2)); + JsonArray targetJson = field.value.getAsJsonArray(); + for(JsonElement arrayItem : targetJson) { + if(schemas.get(indexOfSchema).getType().equals("array")){ + JsonArray nestedArray = arrayItem.getAsJsonArray(); + for(JsonElement nestedArrayItem : nestedArray){ + entries = nestedArrayItem.getAsJsonObject().entrySet(); + putFieldIntoStack(stack, entries, indexOfSchema); + } + } else if (schemas.get(indexOfSchema).getType().equals("object")){ + entries = arrayItem.getAsJsonObject().entrySet(); + putFieldIntoStack(stack, entries, indexOfSchema); + } else { + log.error("record type should be 'array' or 'object'"); + return false; + } + } + + } else if (field.type.equals(TYPE_CHECKING_PASS)) { + // do nothing + fieldCounter += 1; + log.info("Type checking passed : " + field.name); + } else if (field.type.equals(FIELD_NAME_NOT_EXIST)) { + fieldCounter += 1; + isValid = false; + } else { + fieldCounter += 1; + isValid = false; + log.error("Unrecognized type provided: " + field.name + " - " + field.type); + } + + } + log.info("Field Counts: " + Integer.toString(fieldCounter)); + return isValid; + } + +} diff --git a/src/main/java/com/github/sijoonlee/util/JsonUtil.java b/src/main/java/com/github/sijoonlee/util/JsonUtil.java new file mode 100644 index 0000000..18ca7ba --- /dev/null +++ b/src/main/java/com/github/sijoonlee/util/JsonUtil.java @@ -0,0 +1,60 @@ +package com.github.sijoonlee.util; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; + + +public class JsonUtil { + static public Charset encoding = StandardCharsets.UTF_8; + + static public JsonObject ConvertObjToJsonObj(Object src) { + Gson gson = new Gson(); + JsonElement jsonElement = gson.toJsonTree(src); + return (JsonObject) jsonElement; + } + + public static JsonObject convertJsonFileToJsonObject(String filePath) { + JsonObject jsonObject = null; + try { + Gson gson = new Gson(); + jsonObject = gson.fromJson(new FileReader(filePath), JsonObject.class); + } catch (FileNotFoundException ex){ + System.out.println(ex.toString()); + } + return jsonObject; + } + + public static JsonArray convertJsonFileToJsonArray(String filePath) { + JsonArray jsonArray = null; + try { + Gson gson = new Gson(); + jsonArray = gson.fromJson(new FileReader(filePath), JsonArray.class); + } catch (FileNotFoundException ex){ + System.out.println(ex.toString()); + } + + return jsonArray; + } + + + static public String readJsonFileToString(String path) { + try{ + byte[] encoded = Files.readAllBytes(Paths.get(path)); + return new String(encoded, encoding); + } catch (IOException ex) { + System.out.println(ex.toString()); + return null; + } + + } +} \ No newline at end of file diff --git a/src/test/java/TestValidator.java b/src/test/java/TestValidator.java new file mode 100644 index 0000000..101e7d3 --- /dev/null +++ b/src/test/java/TestValidator.java @@ -0,0 +1,46 @@ +import com.github.sijoonlee.SchemaValidator; +import org.junit.Before; +import org.junit.Test; +import static org.junit.Assert.assertTrue; + +public class TestValidator { + + @Test + public void example1() { + + boolean isValid; + + SchemaValidator validator1 = new SchemaValidator("example/example1/objectArrayInObject_schema1.json"); + + isValid = validator1.runWithJsonFile("example/example1/objectArrayInObject.json", "simple.test"); + assertTrue(isValid); + + SchemaValidator validator2 = new SchemaValidator("example/example1/objectArrayInObject_schema2.json"); + isValid = validator2.runWithJsonFile("example/example1/objectArrayInObject.json", "simple.test"); + assertTrue(isValid); + } + + @Test + public void example2() { + boolean isValid; + SchemaValidator validator = new SchemaValidator("example/example2/arraysInsideObject_schema.json"); + isValid = validator.runWithJsonFile("example/example2/arraysInsideObject.json", "simple.test2"); + assertTrue(isValid); + } + + @Test + public void example3() { + boolean isValid; + SchemaValidator validator = new SchemaValidator("example/example3/simpleObjectInArray_schema.json"); + isValid = validator.runWithJsonFile("example/example3/simpleObjectInArray.json", "simple.test3"); + assertTrue(isValid); + } + + @Test + public void example4() { + boolean isValid; + SchemaValidator validator = new SchemaValidator("example/example4/usingRegex_schema.json"); + isValid = validator.runWithJsonFile("example/example4/usingRegex.json", "simple.test4"); + assertTrue(isValid); + } +}