xref: /aosp_15_r20/external/json-schema-validator/doc/specversion.md (revision 78c4dd6aa35290980cdcd1623a7e337e8d021c7c)
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