1*78c4dd6aSAndroid Build Coastguard WorkerThe library supports V4, V6, V7, V2019-09 and V2020-12 JSON schema specifications. By default, V4 is used for backward compatibility. 2*78c4dd6aSAndroid Build Coastguard Worker 3*78c4dd6aSAndroid Build Coastguard Worker### For Users 4*78c4dd6aSAndroid Build Coastguard Worker 5*78c4dd6aSAndroid Build Coastguard Worker#### To create a draft V4 JsonSchemaFactory 6*78c4dd6aSAndroid Build Coastguard Worker 7*78c4dd6aSAndroid Build Coastguard Worker```java 8*78c4dd6aSAndroid Build Coastguard WorkerObjectMapper mapper = new ObjectMapper(); 9*78c4dd6aSAndroid Build Coastguard WorkerJsonSchemaFactory validatorFactory = JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V4)).objectMapper(mapper).build(); 10*78c4dd6aSAndroid Build Coastguard Worker``` 11*78c4dd6aSAndroid Build Coastguard Workeror with default configuration 12*78c4dd6aSAndroid Build Coastguard Worker```java 13*78c4dd6aSAndroid Build Coastguard WorkerJsonSchemaFactory validatorFactory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V4)); 14*78c4dd6aSAndroid Build Coastguard Worker``` 15*78c4dd6aSAndroid Build Coastguard Worker 16*78c4dd6aSAndroid Build Coastguard WorkerPlease avoid using default `getInstance()`, which, internally, defaults to the `SpecVersion.VersionFlag.V4` as the parameter. This is deprecated. 17*78c4dd6aSAndroid Build Coastguard Worker 18*78c4dd6aSAndroid Build Coastguard Worker#### To create a draft V6 JsonSchemaFactory 19*78c4dd6aSAndroid Build Coastguard Worker 20*78c4dd6aSAndroid Build Coastguard Worker```java 21*78c4dd6aSAndroid Build Coastguard WorkerObjectMapper mapper = new ObjectMapper(); 22*78c4dd6aSAndroid Build Coastguard WorkerJsonSchemaFactory validatorFactory = JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V6)).objectMapper(mapper).build(); 23*78c4dd6aSAndroid Build Coastguard Worker``` 24*78c4dd6aSAndroid Build Coastguard Workeror with default configuration 25*78c4dd6aSAndroid Build Coastguard Worker```java 26*78c4dd6aSAndroid Build Coastguard WorkerJsonSchemaFactory validatorFactory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V6)); 27*78c4dd6aSAndroid Build Coastguard Worker``` 28*78c4dd6aSAndroid Build Coastguard Worker 29*78c4dd6aSAndroid Build Coastguard Worker#### To create a draft V7 JsonSchemaFactory 30*78c4dd6aSAndroid Build Coastguard Worker 31*78c4dd6aSAndroid Build Coastguard Worker```java 32*78c4dd6aSAndroid Build Coastguard WorkerObjectMapper mapper = new ObjectMapper(); 33*78c4dd6aSAndroid Build Coastguard WorkerJsonSchemaFactory validatorFactory = JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7)).objectMapper(mapper).build(); 34*78c4dd6aSAndroid Build Coastguard Worker``` 35*78c4dd6aSAndroid Build Coastguard Workeror with default configuration 36*78c4dd6aSAndroid Build Coastguard Worker```java 37*78c4dd6aSAndroid Build Coastguard WorkerJsonSchemaFactory validatorFactory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7)); 38*78c4dd6aSAndroid Build Coastguard Worker``` 39*78c4dd6aSAndroid Build Coastguard Worker 40*78c4dd6aSAndroid Build Coastguard Worker#### To create a draft 2019-09 JsonSchemaFactory 41*78c4dd6aSAndroid Build Coastguard Worker 42*78c4dd6aSAndroid Build Coastguard Worker```java 43*78c4dd6aSAndroid Build Coastguard WorkerObjectMapper mapper = new ObjectMapper(); 44*78c4dd6aSAndroid Build Coastguard WorkerJsonSchemaFactory validatorFactory = JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V201909)).objectMapper(mapper).build(); 45*78c4dd6aSAndroid Build Coastguard Worker``` 46*78c4dd6aSAndroid Build Coastguard Workeror with default configuration 47*78c4dd6aSAndroid Build Coastguard Worker```java 48*78c4dd6aSAndroid Build Coastguard WorkerJsonSchemaFactory validatorFactory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V201909)); 49*78c4dd6aSAndroid Build Coastguard Worker``` 50*78c4dd6aSAndroid Build Coastguard Worker 51*78c4dd6aSAndroid Build Coastguard Worker#### To create a draft 2020-12 JsonSchemaFactory 52*78c4dd6aSAndroid Build Coastguard Worker 53*78c4dd6aSAndroid Build Coastguard Worker```java 54*78c4dd6aSAndroid Build Coastguard WorkerObjectMapper mapper = new ObjectMapper(); 55*78c4dd6aSAndroid Build Coastguard WorkerJsonSchemaFactory validatorFactory = JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V202012)).objectMapper(mapper).build(); 56*78c4dd6aSAndroid Build Coastguard Worker``` 57*78c4dd6aSAndroid Build Coastguard Workeror with default configuration 58*78c4dd6aSAndroid Build Coastguard Worker```java 59*78c4dd6aSAndroid Build Coastguard WorkerJsonSchemaFactory validatorFactory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V202012)); 60*78c4dd6aSAndroid Build Coastguard Worker``` 61*78c4dd6aSAndroid Build Coastguard Worker 62*78c4dd6aSAndroid Build Coastguard Worker#### To create a JsonSchemaFactory, automatically detecting schema version 63*78c4dd6aSAndroid Build Coastguard Worker 64*78c4dd6aSAndroid Build Coastguard Worker```java 65*78c4dd6aSAndroid Build Coastguard WorkerObjectMapper mapper = new ObjectMapper(); 66*78c4dd6aSAndroid Build Coastguard WorkerJsonNode jsonNode = mapper.readTree(/* schema / schema input steam etc. */); 67*78c4dd6aSAndroid Build Coastguard WorkerJsonSchemaFactory validatorFactory = JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(SpecVersionDetector.detect(jsonNode))).objectMapper(mapper).build(); 68*78c4dd6aSAndroid Build Coastguard Worker``` 69*78c4dd6aSAndroid Build Coastguard Workeror with default configuration 70*78c4dd6aSAndroid Build Coastguard Worker```java 71*78c4dd6aSAndroid Build Coastguard WorkerObjectMapper mapper = new ObjectMapper(); 72*78c4dd6aSAndroid Build Coastguard WorkerJsonNode jsonNode = mapper.readTree(/* schema / schema input steam etc. */); 73*78c4dd6aSAndroid Build Coastguard WorkerJsonSchemaFactory validatorFactory = JsonSchemaFactory.getInstance(SpecVersionDetector.detect(jsonNode)); 74*78c4dd6aSAndroid Build Coastguard Worker``` 75*78c4dd6aSAndroid Build Coastguard Worker 76*78c4dd6aSAndroid Build Coastguard Worker### For Developers 77*78c4dd6aSAndroid Build Coastguard Worker 78*78c4dd6aSAndroid Build Coastguard Worker#### SpecVersion 79*78c4dd6aSAndroid Build Coastguard Worker 80*78c4dd6aSAndroid Build Coastguard WorkerA new class `SpecVersion` has been introduced to indicate which version of the specification is used when creating the `JsonSchemaFactory`. The `SpecVersion` has an enum and two methods to convert a long to an `EnumSet` or a set of `VersionFlags` to a long value. 81*78c4dd6aSAndroid Build Coastguard Worker 82*78c4dd6aSAndroid Build Coastguard Worker```java 83*78c4dd6aSAndroid Build Coastguard Workerpublic enum VersionFlag { 84*78c4dd6aSAndroid Build Coastguard Worker 85*78c4dd6aSAndroid Build Coastguard Worker V4(1<<0), 86*78c4dd6aSAndroid Build Coastguard Worker V6(1<<1), 87*78c4dd6aSAndroid Build Coastguard Worker V7(1<<2), 88*78c4dd6aSAndroid Build Coastguard Worker V201909(1<<3), 89*78c4dd6aSAndroid Build Coastguard Worker V202012(1<<4); 90*78c4dd6aSAndroid Build Coastguard Worker 91*78c4dd6aSAndroid Build Coastguard Worker``` 92*78c4dd6aSAndroid Build Coastguard Worker 93*78c4dd6aSAndroid Build Coastguard WorkerIn the long value, we are using 5 bits now as we are supporting 5 versions at the moment. 94*78c4dd6aSAndroid Build Coastguard Worker 95*78c4dd6aSAndroid Build Coastguard WorkerV4 -> 00001 -> 1 96*78c4dd6aSAndroid Build Coastguard WorkerV6 -> 00010 -> 2 97*78c4dd6aSAndroid Build Coastguard WorkerV7 -> 00100 -> 4 98*78c4dd6aSAndroid Build Coastguard WorkerV201909 -> 01000 -> 8 99*78c4dd6aSAndroid Build Coastguard WorkerV202012 -> 10000 --> 16 100*78c4dd6aSAndroid Build Coastguard Worker 101*78c4dd6aSAndroid Build Coastguard WorkerIf we have a new version added, it should be 102*78c4dd6aSAndroid Build Coastguard Worker 103*78c4dd6aSAndroid Build Coastguard WorkerV202209 -> 100000 -> 32 104*78c4dd6aSAndroid Build Coastguard Worker 105*78c4dd6aSAndroid Build Coastguard Worker#### ValidatorTypeCode 106*78c4dd6aSAndroid Build Coastguard Worker 107*78c4dd6aSAndroid Build Coastguard WorkerA new field versionCode is added to indicate which version the validator is supported. 108*78c4dd6aSAndroid Build Coastguard Worker 109*78c4dd6aSAndroid Build Coastguard WorkerFor most of the validators, the version code should be 31, which is 11111. This means the validator will be loaded for every version of the specification. 110*78c4dd6aSAndroid Build Coastguard Worker 111*78c4dd6aSAndroid Build Coastguard WorkerFor example. 112*78c4dd6aSAndroid Build Coastguard Worker 113*78c4dd6aSAndroid Build Coastguard Worker```java 114*78c4dd6aSAndroid Build Coastguard WorkerMAXIMUM("maximum", "1011", new MessageFormat("{0}: must have a maximum value of {1}"), MaximumValidator.class, 31), 115*78c4dd6aSAndroid Build Coastguard Worker``` 116*78c4dd6aSAndroid Build Coastguard Worker 117*78c4dd6aSAndroid Build Coastguard WorkerSince if-then-else was introduced in the V7, it only works for V7, V2019-09 and V2020-12 118*78c4dd6aSAndroid Build Coastguard Worker 119*78c4dd6aSAndroid Build Coastguard Worker```java 120*78c4dd6aSAndroid Build Coastguard WorkerIF_THEN_ELSE("if", "1037", null, IfValidator.class, 28), // V7|V201909|V202012 11100 121*78c4dd6aSAndroid Build Coastguard Worker``` 122*78c4dd6aSAndroid Build Coastguard Worker 123*78c4dd6aSAndroid Build Coastguard WorkerFor exclusiveMaximum, it was introduced from V6 124*78c4dd6aSAndroid Build Coastguard Worker 125*78c4dd6aSAndroid Build Coastguard Worker```java 126*78c4dd6aSAndroid Build Coastguard WorkerEXCLUSIVE_MAXIMUM("exclusiveMaximum", "1038", new MessageFormat("{0}: must have a exclusive maximum value of {1}"), ExclusiveMaximumValidator.class, 30), // V6|V7|V201909|V202012 127*78c4dd6aSAndroid Build Coastguard Worker``` 128*78c4dd6aSAndroid Build Coastguard Worker 129*78c4dd6aSAndroid Build Coastguard WorkerThe getNonFormatKeywords method is updated to accept a SpecVersion.VersionFlag so that only the keywords supported by the specification will be loaded. 130*78c4dd6aSAndroid Build Coastguard Worker 131*78c4dd6aSAndroid Build Coastguard Worker```java 132*78c4dd6aSAndroid Build Coastguard Workerpublic static List<ValidatorTypeCode> getNonFormatKeywords(SpecVersion.VersionFlag versionFlag) { 133*78c4dd6aSAndroid Build Coastguard Worker final List<ValidatorTypeCode> result = new ArrayList<ValidatorTypeCode>(); 134*78c4dd6aSAndroid Build Coastguard Worker for (ValidatorTypeCode keyword: values()) { 135*78c4dd6aSAndroid Build Coastguard Worker if (!FORMAT.equals(keyword) && specVersion.getVersionFlags(keyword.versionCode).contains(versionFlag)) { 136*78c4dd6aSAndroid Build Coastguard Worker result.add(keyword); 137*78c4dd6aSAndroid Build Coastguard Worker } 138*78c4dd6aSAndroid Build Coastguard Worker } 139*78c4dd6aSAndroid Build Coastguard Worker return result; 140*78c4dd6aSAndroid Build Coastguard Worker} 141*78c4dd6aSAndroid Build Coastguard Worker``` 142*78c4dd6aSAndroid Build Coastguard Worker 143*78c4dd6aSAndroid Build Coastguard Worker#### JsonMetaSchema 144*78c4dd6aSAndroid Build Coastguard Worker 145*78c4dd6aSAndroid Build Coastguard WorkerWe have created four different static classes V4, V6, V7, V201909 and V202012 to build different `JsonMetaSchema` instances. 146*78c4dd6aSAndroid Build Coastguard Worker 147*78c4dd6aSAndroid Build Coastguard WorkerFor the BUILDIN_FORMATS, there is a common section, and each static class has its version-specific BUILDIN_FORMATS section. 148*78c4dd6aSAndroid Build Coastguard Worker 149*78c4dd6aSAndroid Build Coastguard Worker#### JsonSchemaFactory 150*78c4dd6aSAndroid Build Coastguard Worker 151*78c4dd6aSAndroid Build Coastguard WorkerThe getInstance supports a parameter `SpecVersion.VersionFlag` to get the right instance of the `JsonMetaShema` to create the factory. If there is no parameter, then V4 is used by default. 152*78c4dd6aSAndroid Build Coastguard Worker 153*78c4dd6aSAndroid Build Coastguard Worker```java 154*78c4dd6aSAndroid Build Coastguard Worker@Deprecated 155*78c4dd6aSAndroid Build Coastguard Workerpublic static JsonSchemaFactory getInstance() { 156*78c4dd6aSAndroid Build Coastguard Worker return getInstance(SpecVersion.VersionFlag.V4); 157*78c4dd6aSAndroid Build Coastguard Worker} 158*78c4dd6aSAndroid Build Coastguard Worker 159*78c4dd6aSAndroid Build Coastguard Workerpublic static JsonSchemaFactory getInstance(SpecVersion.VersionFlag versionFlag) { 160*78c4dd6aSAndroid Build Coastguard Worker JsonSchemaVersion jsonSchemaVersion = checkVersion(versionFlag); 161*78c4dd6aSAndroid Build Coastguard Worker JsonMetaSchema metaSchema = jsonSchemaVersion.getInstance(); 162*78c4dd6aSAndroid Build Coastguard Worker return builder() 163*78c4dd6aSAndroid Build Coastguard Worker .defaultMetaSchemaIri(metaSchema.getIri()) 164*78c4dd6aSAndroid Build Coastguard Worker .metaSchema(metaSchema) 165*78c4dd6aSAndroid Build Coastguard Worker .build(); 166*78c4dd6aSAndroid Build Coastguard Worker} 167*78c4dd6aSAndroid Build Coastguard Worker``` 168*78c4dd6aSAndroid Build Coastguard Worker 169*78c4dd6aSAndroid Build Coastguard Worker#### SpecVersionDetector 170*78c4dd6aSAndroid Build Coastguard Worker 171*78c4dd6aSAndroid Build Coastguard WorkerThis class detects schema version based on the schema tag. 172*78c4dd6aSAndroid Build Coastguard Worker 173*78c4dd6aSAndroid Build Coastguard Worker```java 174*78c4dd6aSAndroid Build Coastguard Workerprivate static final String SCHEMA_TAG = "$schema"; 175*78c4dd6aSAndroid Build Coastguard Worker 176*78c4dd6aSAndroid Build Coastguard Workerpublic static SpecVersion.VersionFlag detect(JsonNode jsonNode) { 177*78c4dd6aSAndroid Build Coastguard Worker if (!jsonNode.has(SCHEMA_TAG)) 178*78c4dd6aSAndroid Build Coastguard Worker throw new JsonSchemaException("Schema tag not present"); 179*78c4dd6aSAndroid Build Coastguard Worker 180*78c4dd6aSAndroid Build Coastguard Worker final boolean forceHttps = true; 181*78c4dd6aSAndroid Build Coastguard Worker final boolean removeEmptyFragmentSuffix = true; 182*78c4dd6aSAndroid Build Coastguard Worker 183*78c4dd6aSAndroid Build Coastguard Worker String schemaUri = JsonSchemaFactory.normalizeMetaSchemaUri(jsonNode.get(SCHEMA_TAG).asText(), forceHttps, removeEmptyFragmentSuffix); 184*78c4dd6aSAndroid Build Coastguard Worker if (schemaUri.equals(JsonMetaSchema.getV4().getIri())) 185*78c4dd6aSAndroid Build Coastguard Worker return SpecVersion.VersionFlag.V4; 186*78c4dd6aSAndroid Build Coastguard Worker else if (schemaUri.equals(JsonMetaSchema.getV6().getIri())) 187*78c4dd6aSAndroid Build Coastguard Worker return SpecVersion.VersionFlag.V6; 188*78c4dd6aSAndroid Build Coastguard Worker else if (schemaUri.equals(JsonMetaSchema.getV7().getIri())) 189*78c4dd6aSAndroid Build Coastguard Worker return SpecVersion.VersionFlag.V7; 190*78c4dd6aSAndroid Build Coastguard Worker else if (schemaUri.equals(JsonMetaSchema.getV201909().getIri())) 191*78c4dd6aSAndroid Build Coastguard Worker return SpecVersion.VersionFlag.V201909; 192*78c4dd6aSAndroid Build Coastguard Worker else if (schemaUri.equals(JsonMetaSchema.getV202012().getIri())) 193*78c4dd6aSAndroid Build Coastguard Worker return SpecVersion.VersionFlag.V202012; 194*78c4dd6aSAndroid Build Coastguard Worker else 195*78c4dd6aSAndroid Build Coastguard Worker throw new JsonSchemaException("Unrecognizable schema"); 196*78c4dd6aSAndroid Build Coastguard Worker} 197*78c4dd6aSAndroid Build Coastguard Worker``` 198*78c4dd6aSAndroid Build Coastguard Worker 199*78c4dd6aSAndroid Build Coastguard Worker### For Testers 200*78c4dd6aSAndroid Build Coastguard Worker 201*78c4dd6aSAndroid Build Coastguard WorkerIn the test resource folder, we have created and copied all draft version's test suite. They are located in draft4, draft6, draft7, draft2019-09 and draft2020-12 folders. 202*78c4dd6aSAndroid Build Coastguard Worker 203*78c4dd6aSAndroid Build Coastguard WorkerThe existing JsonSchemaTest has been renamed to V4JsonSchemaTest, and the following test classes are added. 204*78c4dd6aSAndroid Build Coastguard Worker 205*78c4dd6aSAndroid Build Coastguard Worker``` 206*78c4dd6aSAndroid Build Coastguard WorkerV6JsonSchemaTest 207*78c4dd6aSAndroid Build Coastguard WorkerV7JsonSchemaTest 208*78c4dd6aSAndroid Build Coastguard WorkerV201909JsonSchemaTest 209*78c4dd6aSAndroid Build Coastguard WorkerV202012JsonSchemaTest 210*78c4dd6aSAndroid Build Coastguard Worker``` 211*78c4dd6aSAndroid Build Coastguard Worker 212*78c4dd6aSAndroid Build Coastguard WorkerThese new test classes are not completed yet, and only some sample test cases are added. 213*78c4dd6aSAndroid Build Coastguard Worker 214