1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.juneau.jsonschema.annotation;
18
19 import static org.apache.juneau.TestUtils.*;
20 import static org.apache.juneau.junit.bct.BctAssertions.*;
21 import static org.junit.jupiter.api.Assertions.*;
22
23 import org.apache.juneau.*;
24 import org.apache.juneau.annotation.*;
25 import org.junit.jupiter.api.*;
26
27 class SchemaAnnotation_Test extends TestBase {
28
29 private static final String CNAME = SchemaAnnotation_Test.class.getName();
30
31 private static class X1 {}
32
33
34
35
36
37 Schema a1 = SchemaAnnotation.create()
38 .default_("a")
39 .enum_("b")
40 .$ref("c")
41 .additionalProperties("d")
42 .allOf("e")
43 .cf("f")
44 .collectionFormat("g")
45 .d("h")
46 .description("i")
47 .df("j")
48 .discriminator("k")
49 .e("l")
50 .emax(true)
51 .emin(true)
52 .exclusiveMaximum(true)
53 .exclusiveMinimum(true)
54 .externalDocs(ExternalDocsAnnotation.DEFAULT)
55 .f("m")
56 .format("n")
57 .ignore(true)
58 .items(ItemsAnnotation.DEFAULT)
59 .max("o")
60 .maxi(1)
61 .maximum("p")
62 .maxItems(2)
63 .maxl(3)
64 .maxLength(4)
65 .maxp(5)
66 .maxProperties(6)
67 .min("q")
68 .mini(7)
69 .minimum("r")
70 .minItems(8)
71 .minl(9)
72 .minLength(10)
73 .minp(11)
74 .minProperties(12)
75 .mo("s")
76 .multipleOf("t")
77 .on("u")
78 .onClass(X1.class)
79 .p("v")
80 .pattern("w")
81 .properties("x")
82 .r(true)
83 .readOnly(true)
84 .required(true)
85 .ro(true)
86 .t("z")
87 .title("aa")
88 .type("bb")
89 .ui(true)
90 .uniqueItems(true)
91 .xml("cc")
92 .build();
93
94 Schema a2 = SchemaAnnotation.create()
95 .default_("a")
96 .enum_("b")
97 .$ref("c")
98 .additionalProperties("d")
99 .allOf("e")
100 .cf("f")
101 .collectionFormat("g")
102 .d("h")
103 .description("i")
104 .df("j")
105 .discriminator("k")
106 .e("l")
107 .emax(true)
108 .emin(true)
109 .exclusiveMaximum(true)
110 .exclusiveMinimum(true)
111 .externalDocs(ExternalDocsAnnotation.DEFAULT)
112 .f("m")
113 .format("n")
114 .ignore(true)
115 .items(ItemsAnnotation.DEFAULT)
116 .max("o")
117 .maxi(1)
118 .maximum("p")
119 .maxItems(2)
120 .maxl(3)
121 .maxLength(4)
122 .maxp(5)
123 .maxProperties(6)
124 .min("q")
125 .mini(7)
126 .minimum("r")
127 .minItems(8)
128 .minl(9)
129 .minLength(10)
130 .minp(11)
131 .minProperties(12)
132 .mo("s")
133 .multipleOf("t")
134 .on("u")
135 .onClass(X1.class)
136 .p("v")
137 .pattern("w")
138 .properties("x")
139 .r(true)
140 .readOnly(true)
141 .required(true)
142 .ro(true)
143 .t("z")
144 .title("aa")
145 .type("bb")
146 .ui(true)
147 .uniqueItems(true)
148 .xml("cc")
149 .build();
150
151 @Test void a01_basic() {
152 assertBean(a1,
153 "$ref,default_,enum_,additionalProperties,aev,allOf,allowEmptyValue,cf,collectionFormat,d,description,df,discriminator,e,emax,emin,exclusiveMaximum,exclusiveMinimum,externalDocs{description,url},f,format,ignore,items{$ref,default_,enum_,cf,collectionFormat,description,df,e,emax,emin,exclusiveMaximum,exclusiveMinimum,f,format,items{$ref,default_,enum_,cf,collectionFormat,description,df,e,emax,emin,exclusiveMaximum,exclusiveMinimum,f,format,items,max,maxItems,maxLength,maxi,maximum,maxl,min,minItems,minLength,mini,minimum,minl,mo,multipleOf,p,pattern,t,type,ui,uniqueItems},max,maxItems,maxLength,maxi,maximum,maxl,min,minItems,minLength,mini,minimum,minl,mo,multipleOf,p,pattern,t,type,ui,uniqueItems},max,maxItems,maxLength,maxProperties,maxi,maximum,maxl,maxp,min,minItems,minLength,minProperties,mini,minimum,minl,minp,mo,multipleOf,on,onClass,p,pattern,properties,r,readOnly,required,ro,sie,skipIfEmpty,t,title,type,ui,uniqueItems,xml",
154 "c,[a],[b],[d],false,[e],false,f,g,[h],[i],[j],k,[l],true,true,true,true,{[],},m,n,true,{,[],[],,,[],[],[],false,false,false,false,,,{,[],[],,,[],[],[],false,false,false,false,,,[],,-1,-1,-1,,-1,,-1,-1,-1,,-1,,,,,,,false,false},,-1,-1,-1,,-1,,-1,-1,-1,,-1,,,,,,,false,false},o,2,4,6,1,p,3,5,q,8,10,12,7,r,9,11,s,t,[u],[X1],v,w,[x],true,true,true,true,false,false,z,aa,bb,true,true,[cc]");
155 }
156
157 @Test void a02_testEquivalency() {
158 assertEquals(a2, a1);
159 assertNotEqualsAny(a1.hashCode(), 0, -1);
160 assertEquals(a1.hashCode(), a2.hashCode());
161 }
162
163
164
165
166
167 @Test void b01_testEquivalencyInPropertyStores() {
168 var bc1 = BeanContext.create().annotations(a1).build();
169 var bc2 = BeanContext.create().annotations(a2).build();
170 assertSame(bc1, bc2);
171 }
172
173
174
175
176
177 public static class C1 {
178 public int f1;
179 public void m1() {}
180 }
181 public static class C2 {
182 public int f2;
183 public void m2() {}
184 }
185
186 @Test void c01_otherMethods() throws Exception {
187 var c1 = SchemaAnnotation.create(C1.class).on(C2.class).build();
188 var c2 = SchemaAnnotation.create("a").on("b").build();
189 var c3 = SchemaAnnotation.create().on(C1.class.getField("f1")).on(C2.class.getField("f2")).build();
190 var c4 = SchemaAnnotation.create().on(C1.class.getMethod("m1")).on(C2.class.getMethod("m2")).build();
191
192 assertBean(c1, "on", "["+CNAME+"$C1,"+CNAME+"$C2]");
193 assertBean(c2, "on", "[a,b]");
194 assertBean(c3, "on", "["+CNAME+"$C1.f1,"+CNAME+"$C2.f2]");
195 assertBean(c4, "on", "["+CNAME+"$C1.m1(),"+CNAME+"$C2.m2()]");
196 }
197
198
199
200
201
202 @Schema(
203 default_="a",
204 enum_="b",
205 $ref="c",
206 additionalProperties="d",
207 allOf="e",
208 cf="f",
209 collectionFormat="g",
210 d="h",
211 description="i",
212 df="j",
213 discriminator="k",
214 e="l",
215 emax=true,
216 emin=true,
217 exclusiveMaximum=true,
218 exclusiveMinimum=true,
219 externalDocs=@ExternalDocs,
220 f="m",
221 format="n",
222 ignore=true,
223 items=@Items,
224 max="o",
225 maxi=1,
226 maximum="p",
227 maxItems=2,
228 maxl=3,
229 maxLength=4,
230 maxp=5,
231 maxProperties=6,
232 min="q",
233 mini=7,
234 minimum="r",
235 minItems=8,
236 minl=9,
237 minLength=10,
238 minp=11,
239 minProperties=12,
240 mo="s",
241 multipleOf="t",
242 on="u",
243 onClass=X1.class,
244 p="v",
245 pattern="w",
246 properties="x",
247 r=true,
248 readOnly=true,
249 required=true,
250 ro=true,
251 t="z",
252 title="aa",
253 type="bb",
254 ui=true,
255 uniqueItems=true,
256 xml="cc"
257 )
258 public static class D1 {}
259 Schema d1 = D1.class.getAnnotationsByType(Schema.class)[0];
260
261 @Schema(
262 default_="a",
263 enum_="b",
264 $ref="c",
265 additionalProperties="d",
266 allOf="e",
267 cf="f",
268 collectionFormat="g",
269 d="h",
270 description="i",
271 df="j",
272 discriminator="k",
273 e="l",
274 emax=true,
275 emin=true,
276 exclusiveMaximum=true,
277 exclusiveMinimum=true,
278 externalDocs=@ExternalDocs,
279 f="m",
280 format="n",
281 ignore=true,
282 items=@Items,
283 max="o",
284 maxi=1,
285 maximum="p",
286 maxItems=2,
287 maxl=3,
288 maxLength=4,
289 maxp=5,
290 maxProperties=6,
291 min="q",
292 mini=7,
293 minimum="r",
294 minItems=8,
295 minl=9,
296 minLength=10,
297 minp=11,
298 minProperties=12,
299 mo="s",
300 multipleOf="t",
301 on="u",
302 onClass=X1.class,
303 p="v",
304 pattern="w",
305 properties="x",
306 r=true,
307 readOnly=true,
308 required=true,
309 ro=true,
310 t="z",
311 title="aa",
312 type="bb",
313 ui=true,
314 uniqueItems=true,
315 xml="cc"
316 )
317 public static class D2 {}
318 Schema d2 = D2.class.getAnnotationsByType(Schema.class)[0];
319
320 @Test void d01_comparisonWithDeclarativeAnnotations() {
321 assertEqualsAll(a1, d1, d2);
322 assertNotEqualsAny(a1.hashCode(), 0, -1);
323 assertEqualsAll(a1.hashCode(), d1.hashCode(), d2.hashCode());
324 }
325
326
327
328
329
330 Schema draft2020_1 = SchemaAnnotation.create()
331 .const_("constantValue")
332 .examples("example1", "example2")
333 .$comment("This is a schema comment")
334 .deprecatedProperty(true)
335 .exclusiveMaximumValue("100")
336 .exclusiveMinimumValue("0")
337 .contentMediaType("application/json")
338 .contentEncoding("base64")
339 .prefixItems("string", "number")
340 .unevaluatedItems("false")
341 .unevaluatedProperties("false")
342 .dependentSchemas("prop1:{type:'string'}")
343 .dependentRequired("prop1:prop2,prop3")
344 .if_("properties:{foo:{const:'bar'}}")
345 .then_("required:['baz']")
346 .else_("required:['qux']")
347 .$defs("MyDef:{type:'string'}")
348 .$id("https://example.com/schemas/my-schema")
349 .build();
350
351 Schema draft2020_2 = SchemaAnnotation.create()
352 .const_("constantValue")
353 .examples("example1", "example2")
354 .$comment("This is a schema comment")
355 .deprecatedProperty(true)
356 .exclusiveMaximumValue("100")
357 .exclusiveMinimumValue("0")
358 .contentMediaType("application/json")
359 .contentEncoding("base64")
360 .prefixItems("string", "number")
361 .unevaluatedItems("false")
362 .unevaluatedProperties("false")
363 .dependentSchemas("prop1:{type:'string'}")
364 .dependentRequired("prop1:prop2,prop3")
365 .if_("properties:{foo:{const:'bar'}}")
366 .then_("required:['baz']")
367 .else_("required:['qux']")
368 .$defs("MyDef:{type:'string'}")
369 .$id("https://example.com/schemas/my-schema")
370 .build();
371
372 @Test void e01_draft2020_basic() {
373 assertBean(draft2020_1,
374 "$comment,$defs,$id,const_,else_,if_,then_,contentEncoding,contentMediaType,dependentRequired,dependentSchemas,deprecatedProperty,examples,exclusiveMaximumValue,exclusiveMinimumValue,prefixItems,unevaluatedItems,unevaluatedProperties",
375 "[This is a schema comment],[MyDef:{type:'string'}],https://example.com/schemas/my-schema,[constantValue],[required:['qux']],[properties:{foo:{const:'bar'}}],[required:['baz']],base64,application/json,[prop1:prop2,prop3],[prop1:{type:'string'}],true,[example1,example2],100,0,[string,number],[false],[false]");
376 }
377
378 @Test void e02_draft2020_testEquivalency() {
379 assertEquals(draft2020_2, draft2020_1);
380 assertNotEqualsAny(draft2020_1.hashCode(), 0, -1);
381 assertEquals(draft2020_1.hashCode(), draft2020_2.hashCode());
382 }
383
384 @Test void e03_draft2020_testEquivalencyInPropertyStores() {
385 var bc1 = BeanContext.create().annotations(draft2020_1).build();
386 var bc2 = BeanContext.create().annotations(draft2020_2).build();
387 assertSame(bc1, bc2);
388 }
389
390 @Schema(
391 const_="constantValue",
392 examples={"example1", "example2"},
393 $comment="This is a schema comment",
394 deprecatedProperty=true,
395 exclusiveMaximumValue="100",
396 exclusiveMinimumValue="0",
397 contentMediaType="application/json",
398 contentEncoding="base64",
399 prefixItems={"string", "number"},
400 unevaluatedItems="false",
401 unevaluatedProperties="false",
402 dependentSchemas="prop1:{type:'string'}",
403 dependentRequired="prop1:prop2,prop3",
404 if_="properties:{foo:{const:'bar'}}",
405 then_="required:['baz']",
406 else_="required:['qux']",
407 $defs="MyDef:{type:'string'}",
408 $id="https://example.com/schemas/my-schema"
409 )
410 public static class E1 {}
411 Schema e1 = E1.class.getAnnotationsByType(Schema.class)[0];
412
413 @Schema(
414 const_="constantValue",
415 examples={"example1", "example2"},
416 $comment="This is a schema comment",
417 deprecatedProperty=true,
418 exclusiveMaximumValue="100",
419 exclusiveMinimumValue="0",
420 contentMediaType="application/json",
421 contentEncoding="base64",
422 prefixItems={"string", "number"},
423 unevaluatedItems="false",
424 unevaluatedProperties="false",
425 dependentSchemas="prop1:{type:'string'}",
426 dependentRequired="prop1:prop2,prop3",
427 if_="properties:{foo:{const:'bar'}}",
428 then_="required:['baz']",
429 else_="required:['qux']",
430 $defs="MyDef:{type:'string'}",
431 $id="https://example.com/schemas/my-schema"
432 )
433 public static class E2 {}
434 Schema e2 = E2.class.getAnnotationsByType(Schema.class)[0];
435
436 @Test void e04_draft2020_comparisonWithDeclarativeAnnotations() {
437 assertEqualsAll(draft2020_1, e1, e2);
438 assertNotEqualsAny(draft2020_1.hashCode(), 0, -1);
439 assertEqualsAll(draft2020_1.hashCode(), e1.hashCode(), e2.hashCode());
440 }
441
442
443
444
445
446 @Test void f01_backwardCompatibility_exclusiveMaxMin() {
447
448 Schema oldStyle = SchemaAnnotation.create()
449 .exclusiveMaximum(true)
450 .exclusiveMinimum(true)
451 .maximum("100")
452 .minimum("0")
453 .build();
454
455 assertBean(oldStyle, "exclusiveMaximum,exclusiveMinimum,maximum,minimum", "true,true,100,0");
456
457
458 Schema newStyle = SchemaAnnotation.create()
459 .exclusiveMaximumValue("100")
460 .exclusiveMinimumValue("0")
461 .build();
462
463 assertBean(newStyle, "exclusiveMaximumValue,exclusiveMinimumValue", "100,0");
464
465
466 Schema mixed = SchemaAnnotation.create()
467 .exclusiveMaximum(false)
468 .exclusiveMinimum(false)
469 .exclusiveMaximumValue("100")
470 .exclusiveMinimumValue("0")
471 .build();
472
473 assertBean(mixed, "exclusiveMaximum,exclusiveMinimum,exclusiveMaximumValue,exclusiveMinimumValue", "false,false,100,0");
474 }
475 }