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