001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.annotation;
018
019import static java.lang.annotation.ElementType.*;
020import static java.lang.annotation.RetentionPolicy.*;
021import static org.apache.juneau.commons.utils.CollectionUtils.*;
022import static org.apache.juneau.jsonschema.SchemaUtils.*;
023
024import java.lang.annotation.*;
025import java.lang.reflect.*;
026import java.util.*;
027import java.util.function.*;
028
029import org.apache.juneau.*;
030import org.apache.juneau.collections.*;
031import org.apache.juneau.commons.annotation.*;
032import org.apache.juneau.commons.reflect.*;
033import org.apache.juneau.commons.utils.*;
034import org.apache.juneau.parser.*;
035import org.apache.juneau.svl.*;
036
037/**
038 * Utility classes and methods for the {@link Schema @Schema} annotation.
039 *
040 */
041public class SchemaAnnotation {
042   /**
043    * Applies targeted {@link Schema} annotations to a {@link org.apache.juneau.Context.Builder}.
044    */
045   public static class Apply extends AnnotationApplier<Schema,Context.Builder> {
046
047      /**
048       * Constructor.
049       *
050       * @param vr The resolver for resolving values in annotations.
051       */
052      public Apply(VarResolverSession vr) {
053         super(Schema.class, Context.Builder.class, vr);
054      }
055
056      @Override
057      public void apply(AnnotationInfo<Schema> ai, Context.Builder b) {
058         Schema a = ai.inner();
059         if (isEmptyArray(a.on()) && isEmptyArray(a.onClass()))
060            return;
061         b.annotations(a);
062      }
063   }
064
065   /**
066    * A collection of {@link Schema @Schema annotations}.
067    */
068   @Documented
069   @Target({ METHOD, TYPE })
070   @Retention(RUNTIME)
071   @Inherited
072   public static @interface Array {
073
074      /**
075       * The child annotations.
076       *
077       * @return The annotation value.
078       */
079      Schema[] value();
080   }
081
082   /**
083    * Builder class.
084    *
085    * <h5 class='section'>See Also:</h5><ul>
086    *    <li class='jm'>{@link org.apache.juneau.BeanContext.Builder#annotations(Annotation...)}
087    * </ul>
088    */
089   public static class Builder extends AppliedAnnotationObject.BuilderTMF {
090
091      private boolean aev, allowEmptyValue, emax, emin, exclusiveMaximum, exclusiveMinimum, ignore, r, readOnly, required, ro, sie, skipIfEmpty, ui, uniqueItems;
092      private ExternalDocs externalDocs = ExternalDocsAnnotation.DEFAULT;
093      private Items items = ItemsAnnotation.DEFAULT;
094      private long maxi = -1, maxItems = -1, maxl = -1, maxLength = -1, maxp = -1, maxProperties = -1, mini = -1, minItems = -1, minl = -1, minLength = -1, minp = -1, minProperties = -1;
095      private String $ref = "", cf = "", collectionFormat = "", discriminator = "", f = "", format = "", max = "", maximum = "", min = "", minimum = "", mo = "", multipleOf = "", p = "",
096         pattern = "", t = "", title = "", type = "";
097      private String[] default_ = {}, enum_ = {}, additionalProperties = {}, allOf = {}, d = {}, description = {}, df = {}, e = {}, properties = {}, xml = {};
098      private boolean deprecatedProperty;
099      private String $id = "", contentMediaType = "", contentEncoding = "", exclusiveMaximumValue = "", exclusiveMinimumValue = "";
100      private String[] const_ = {}, examples = {}, $comment = {}, prefixItems = {}, unevaluatedItems = {}, unevaluatedProperties = {}, dependentSchemas = {}, dependentRequired = {}, if_ = {},
101         then_ = {}, else_ = {}, $defs = {};
102
103      /**
104       * Constructor.
105       */
106      protected Builder() {
107         super(Schema.class);
108      }
109
110      /**
111       * Sets the {@link Schema#const_} property on this annotation.
112       *
113       * @param value The new value for this property.
114       * @return This object.
115       */
116      public Builder const_(String...value) {
117         const_ = value;
118         return this;
119      }
120
121      /**
122       * Sets the {@link Schema#default_} property on this annotation.
123       *
124       * @param value The new value for this property.
125       * @return This object.
126       */
127      public Builder default_(String...value) {
128         default_ = value;
129         return this;
130      }
131
132      /**
133       * Sets the {@link Schema#else_} property on this annotation.
134       *
135       * @param value The new value for this property.
136       * @return This object.
137       */
138      public Builder else_(String...value) {
139         else_ = value;
140         return this;
141      }
142
143      /**
144       * Sets the {@link Schema#enum_} property on this annotation.
145       *
146       * @param value The new value for this property.
147       * @return This object.
148       */
149      public Builder enum_(String...value) {
150         enum_ = value;
151         return this;
152      }
153
154      /**
155       * Sets the {@link Schema#if_} property on this annotation.
156       *
157       * @param value The new value for this property.
158       * @return This object.
159       */
160      public Builder if_(String...value) {
161         if_ = value;
162         return this;
163      }
164
165      /**
166       * Sets the {@link Schema#then_} property on this annotation.
167       *
168       * @param value The new value for this property.
169       * @return This object.
170       */
171      public Builder then_(String...value) {
172         then_ = value;
173         return this;
174      }
175
176      /**
177       * Sets the {@link Schema#$comment} property on this annotation.
178       *
179       * @param value The new value for this property.
180       * @return This object.
181       */
182      public Builder $comment(String...value) {
183         this.$comment = value;
184         return this;
185      }
186
187      /**
188       * Sets the {@link Schema#$defs} property on this annotation.
189       *
190       * @param value The new value for this property.
191       * @return This object.
192       */
193      public Builder $defs(String...value) {
194         this.$defs = value;
195         return this;
196      }
197
198      /**
199       * Sets the {@link Schema#$id} property on this annotation.
200       *
201       * @param value The new value for this property.
202       * @return This object.
203       */
204      public Builder $id(String value) {
205         this.$id = value;
206         return this;
207      }
208
209      /**
210       * Sets the {@link Schema#$ref} property on this annotation.
211       *
212       * @param value The new value for this property.
213       * @return This object.
214       */
215      public Builder $ref(String value) {
216         this.$ref = value;
217         return this;
218      }
219
220      /**
221       * Sets the {@link Schema#additionalProperties} property on this annotation.
222       *
223       * @param value The new value for this property.
224       * @return This object.
225       */
226      public Builder additionalProperties(String...value) {
227         additionalProperties = value;
228         return this;
229      }
230
231      /**
232       * Sets the {@link Schema#aev} property on this annotation.
233       *
234       * @param value The new value for this property.
235       * @return This object.
236       */
237      public Builder aev(boolean value) {
238         aev = value;
239         return this;
240      }
241
242      /**
243       * Sets the {@link Schema#allOf} property on this annotation.
244       *
245       * @param value The new value for this property.
246       * @return This object.
247       */
248      public Builder allOf(String...value) {
249         allOf = value;
250         return this;
251      }
252
253      /**
254       * Sets the {@link Schema#allowEmptyValue} property on this annotation.
255       *
256       * @param value The new value for this property.
257       * @return This object.
258       */
259      public Builder allowEmptyValue(boolean value) {
260         allowEmptyValue = value;
261         return this;
262      }
263
264      /**
265       * Instantiates a new {@link Schema @Schema} object initialized with this builder.
266       *
267       * @return A new {@link Schema @Schema} object.
268       */
269      public Schema build() {
270         return new Object(this);
271      }
272
273      /**
274       * Sets the description property on this annotation.
275       *
276       * @param value The new value for this property.
277       * @return This object.
278       */
279      public Builder description(String...value) {
280         description = value;
281         return this;
282      }
283
284      /**
285       * Sets the {@link Schema#cf} property on this annotation.
286       *
287       * @param value The new value for this property.
288       * @return This object.
289       */
290      public Builder cf(String value) {
291         cf = value;
292         return this;
293      }
294
295      /**
296       * Sets the {@link Schema#collectionFormat} property on this annotation.
297       *
298       * @param value The new value for this property.
299       * @return This object.
300       */
301      public Builder collectionFormat(String value) {
302         collectionFormat = value;
303         return this;
304      }
305
306      /**
307       * Sets the {@link Schema#contentEncoding} property on this annotation.
308       *
309       * @param value The new value for this property.
310       * @return This object.
311       */
312      public Builder contentEncoding(String value) {
313         contentEncoding = value;
314         return this;
315      }
316
317      /**
318       * Sets the {@link Schema#contentMediaType} property on this annotation.
319       *
320       * @param value The new value for this property.
321       * @return This object.
322       */
323      public Builder contentMediaType(String value) {
324         contentMediaType = value;
325         return this;
326      }
327
328      /**
329       * Sets the {@link Schema#d} property on this annotation.
330       *
331       * @param value The new value for this property.
332       * @return This object.
333       */
334      public Builder d(String...value) {
335         d = value;
336         return this;
337      }
338
339      /**
340       * Sets the {@link Schema#dependentRequired} property on this annotation.
341       *
342       * @param value The new value for this property.
343       * @return This object.
344       */
345      public Builder dependentRequired(String...value) {
346         dependentRequired = value;
347         return this;
348      }
349
350      /**
351       * Sets the {@link Schema#dependentSchemas} property on this annotation.
352       *
353       * @param value The new value for this property.
354       * @return This object.
355       */
356      public Builder dependentSchemas(String...value) {
357         dependentSchemas = value;
358         return this;
359      }
360
361      /**
362       * Sets the {@link Schema#deprecatedProperty} property on this annotation.
363       *
364       * @param value The new value for this property.
365       * @return This object.
366       */
367      public Builder deprecatedProperty(boolean value) {
368         deprecatedProperty = value;
369         return this;
370      }
371
372      /**
373       * Sets the {@link Schema#df} property on this annotation.
374       *
375       * @param value The new value for this property.
376       * @return This object.
377       */
378      public Builder df(String...value) {
379         df = value;
380         return this;
381      }
382
383      /**
384       * Sets the {@link Schema#discriminator} property on this annotation.
385       *
386       * @param value The new value for this property.
387       * @return This object.
388       */
389      public Builder discriminator(String value) {
390         discriminator = value;
391         return this;
392      }
393
394      /**
395       * Sets the {@link Schema#e} property on this annotation.
396       *
397       * @param value The new value for this property.
398       * @return This object.
399       */
400      public Builder e(String...value) {
401         e = value;
402         return this;
403      }
404
405      /**
406       * Sets the {@link Schema#emax} property on this annotation.
407       *
408       * @param value The new value for this property.
409       * @return This object.
410       */
411      public Builder emax(boolean value) {
412         emax = value;
413         return this;
414      }
415
416      /**
417       * Sets the {@link Schema#emin} property on this annotation.
418       *
419       * @param value The new value for this property.
420       * @return This object.
421       */
422      public Builder emin(boolean value) {
423         emin = value;
424         return this;
425      }
426
427      /**
428       * Sets the {@link Schema#examples} property on this annotation.
429       *
430       * @param value The new value for this property.
431       * @return This object.
432       */
433      public Builder examples(String...value) {
434         examples = value;
435         return this;
436      }
437
438      /**
439       * Sets the {@link Schema#exclusiveMaximum} property on this annotation.
440       *
441       * @param value The new value for this property.
442       * @return This object.
443       */
444      public Builder exclusiveMaximum(boolean value) {
445         exclusiveMaximum = value;
446         return this;
447      }
448
449      /**
450       * Sets the {@link Schema#exclusiveMaximumValue} property on this annotation.
451       *
452       * @param value The new value for this property.
453       * @return This object.
454       */
455      public Builder exclusiveMaximumValue(String value) {
456         exclusiveMaximumValue = value;
457         return this;
458      }
459
460      /**
461       * Sets the {@link Schema#exclusiveMinimum} property on this annotation.
462       *
463       * @param value The new value for this property.
464       * @return This object.
465       */
466      public Builder exclusiveMinimum(boolean value) {
467         exclusiveMinimum = value;
468         return this;
469      }
470
471      /**
472       * Sets the {@link Schema#exclusiveMinimumValue} property on this annotation.
473       *
474       * @param value The new value for this property.
475       * @return This object.
476       */
477      public Builder exclusiveMinimumValue(String value) {
478         exclusiveMinimumValue = value;
479         return this;
480      }
481
482      /**
483       * Sets the {@link Schema#externalDocs} property on this annotation.
484       *
485       * @param value The new value for this property.
486       * @return This object.
487       */
488      public Builder externalDocs(ExternalDocs value) {
489         externalDocs = value;
490         return this;
491      }
492
493      /**
494       * Sets the {@link Schema#f} property on this annotation.
495       *
496       * @param value The new value for this property.
497       * @return This object.
498       */
499      public Builder f(String value) {
500         f = value;
501         return this;
502      }
503
504      /**
505       * Sets the {@link Schema#format} property on this annotation.
506       *
507       * @param value The new value for this property.
508       * @return This object.
509       */
510      public Builder format(String value) {
511         format = value;
512         return this;
513      }
514
515      /**
516       * Sets the {@link Schema#ignore} property on this annotation.
517       *
518       * @param value The new value for this property.
519       * @return This object.
520       */
521      public Builder ignore(boolean value) {
522         ignore = value;
523         return this;
524      }
525
526      /**
527       * Sets the {@link Schema#items} property on this annotation.
528       *
529       * @param value The new value for this property.
530       * @return This object.
531       */
532      public Builder items(Items value) {
533         items = value;
534         return this;
535      }
536
537      /**
538       * Sets the {@link Schema#max} property on this annotation.
539       *
540       * @param value The new value for this property.
541       * @return This object.
542       */
543      public Builder max(String value) {
544         max = value;
545         return this;
546      }
547
548      /**
549       * Sets the {@link Schema#maxi} property on this annotation.
550       *
551       * @param value The new value for this property.
552       * @return This object.
553       */
554      public Builder maxi(long value) {
555         maxi = value;
556         return this;
557      }
558
559      /**
560       * Sets the {@link Schema#maximum} property on this annotation.
561       *
562       * @param value The new value for this property.
563       * @return This object.
564       */
565      public Builder maximum(String value) {
566         maximum = value;
567         return this;
568      }
569
570      /**
571       * Sets the {@link Schema#maxItems} property on this annotation.
572       *
573       * @param value The new value for this property.
574       * @return This object.
575       */
576      public Builder maxItems(long value) {
577         maxItems = value;
578         return this;
579      }
580
581      /**
582       * Sets the {@link Schema#maxl} property on this annotation.
583       *
584       * @param value The new value for this property.
585       * @return This object.
586       */
587      public Builder maxl(long value) {
588         maxl = value;
589         return this;
590      }
591
592      /**
593       * Sets the {@link Schema#maxLength} property on this annotation.
594       *
595       * @param value The new value for this property.
596       * @return This object.
597       */
598      public Builder maxLength(long value) {
599         maxLength = value;
600         return this;
601      }
602
603      /**
604       * Sets the {@link Schema#maxp} property on this annotation.
605       *
606       * @param value The new value for this property.
607       * @return This object.
608       */
609      public Builder maxp(long value) {
610         maxp = value;
611         return this;
612      }
613
614      /**
615       * Sets the {@link Schema#maxProperties} property on this annotation.
616       *
617       * @param value The new value for this property.
618       * @return This object.
619       */
620      public Builder maxProperties(long value) {
621         maxProperties = value;
622         return this;
623      }
624
625      /**
626       * Sets the {@link Schema#min} property on this annotation.
627       *
628       * @param value The new value for this property.
629       * @return This object.
630       */
631      public Builder min(String value) {
632         min = value;
633         return this;
634      }
635
636      /**
637       * Sets the {@link Schema#mini} property on this annotation.
638       *
639       * @param value The new value for this property.
640       * @return This object.
641       */
642      public Builder mini(long value) {
643         mini = value;
644         return this;
645      }
646
647      /**
648       * Sets the {@link Schema#minimum} property on this annotation.
649       *
650       * @param value The new value for this property.
651       * @return This object.
652       */
653      public Builder minimum(String value) {
654         minimum = value;
655         return this;
656      }
657
658      /**
659       * Sets the {@link Schema#minItems} property on this annotation.
660       *
661       * @param value The new value for this property.
662       * @return This object.
663       */
664      public Builder minItems(long value) {
665         minItems = value;
666         return this;
667      }
668
669      /**
670       * Sets the {@link Schema#minl} property on this annotation.
671       *
672       * @param value The new value for this property.
673       * @return This object.
674       */
675      public Builder minl(long value) {
676         minl = value;
677         return this;
678      }
679
680      /**
681       * Sets the {@link Schema#minLength} property on this annotation.
682       *
683       * @param value The new value for this property.
684       * @return This object.
685       */
686      public Builder minLength(long value) {
687         minLength = value;
688         return this;
689      }
690
691      /**
692       * Sets the {@link Schema#minp} property on this annotation.
693       *
694       * @param value The new value for this property.
695       * @return This object.
696       */
697      public Builder minp(long value) {
698         minp = value;
699         return this;
700      }
701
702      /**
703       * Sets the {@link Schema#minProperties} property on this annotation.
704       *
705       * @param value The new value for this property.
706       * @return This object.
707       */
708      public Builder minProperties(long value) {
709         minProperties = value;
710         return this;
711      }
712
713      /**
714       * Sets the {@link Schema#mo} property on this annotation.
715       *
716       * @param value The new value for this property.
717       * @return This object.
718       */
719      public Builder mo(String value) {
720         mo = value;
721         return this;
722      }
723
724      /**
725       * Sets the {@link Schema#multipleOf} property on this annotation.
726       *
727       * @param value The new value for this property.
728       * @return This object.
729       */
730      public Builder multipleOf(String value) {
731         multipleOf = value;
732         return this;
733      }
734
735      // -----------------------------------------------------------------------------------------------------------------
736      // JSON Schema Draft 2020-12 property setters
737      // -----------------------------------------------------------------------------------------------------------------
738
739      /**
740       * Sets the {@link Schema#p} property on this annotation.
741       *
742       * @param value The new value for this property.
743       * @return This object.
744       */
745      public Builder p(String value) {
746         p = value;
747         return this;
748      }
749
750      /**
751       * Sets the {@link Schema#pattern} property on this annotation.
752       *
753       * @param value The new value for this property.
754       * @return This object.
755       */
756      public Builder pattern(String value) {
757         pattern = value;
758         return this;
759      }
760
761      /**
762       * Sets the {@link Schema#prefixItems} property on this annotation.
763       *
764       * @param value The new value for this property.
765       * @return This object.
766       */
767      public Builder prefixItems(String...value) {
768         prefixItems = value;
769         return this;
770      }
771
772      /**
773       * Sets the {@link Schema#properties} property on this annotation.
774       *
775       * @param value The new value for this property.
776       * @return This object.
777       */
778      public Builder properties(String...value) {
779         properties = value;
780         return this;
781      }
782
783      /**
784       * Sets the {@link Schema#r} property on this annotation.
785       *
786       * @param value The new value for this property.
787       * @return This object.
788       */
789      public Builder r(boolean value) {
790         r = value;
791         return this;
792      }
793
794      /**
795       * Sets the {@link Schema#readOnly} property on this annotation.
796       *
797       * @param value The new value for this property.
798       * @return This object.
799       */
800      public Builder readOnly(boolean value) {
801         readOnly = value;
802         return this;
803      }
804
805      /**
806       * Sets the {@link Schema#required} property on this annotation.
807       *
808       * @param value The new value for this property.
809       * @return This object.
810       */
811      public Builder required(boolean value) {
812         required = value;
813         return this;
814      }
815
816      /**
817       * Sets the {@link Schema#ro} property on this annotation.
818       *
819       * @param value The new value for this property.
820       * @return This object.
821       */
822      public Builder ro(boolean value) {
823         ro = value;
824         return this;
825      }
826
827      /**
828       * Sets the {@link Schema#sie} property on this annotation.
829       *
830       * @param value The new value for this property.
831       * @return This object.
832       */
833      public Builder sie(boolean value) {
834         sie = value;
835         return this;
836      }
837
838      /**
839       * Sets the {@link Schema#skipIfEmpty} property on this annotation.
840       *
841       * @param value The new value for this property.
842       * @return This object.
843       */
844      public Builder skipIfEmpty(boolean value) {
845         skipIfEmpty = value;
846         return this;
847      }
848
849      /**
850       * Sets the {@link Schema#t} property on this annotation.
851       *
852       * @param value The new value for this property.
853       * @return This object.
854       */
855      public Builder t(String value) {
856         t = value;
857         return this;
858      }
859
860      /**
861       * Sets the {@link Schema#title} property on this annotation.
862       *
863       * @param value The new value for this property.
864       * @return This object.
865       */
866      public Builder title(String value) {
867         title = value;
868         return this;
869      }
870
871      /**
872       * Sets the {@link Schema#type} property on this annotation.
873       *
874       * @param value The new value for this property.
875       * @return This object.
876       */
877      public Builder type(String value) {
878         type = value;
879         return this;
880      }
881
882      /**
883       * Sets the {@link Schema#ui} property on this annotation.
884       *
885       * @param value The new value for this property.
886       * @return This object.
887       */
888      public Builder ui(boolean value) {
889         ui = value;
890         return this;
891      }
892
893      /**
894       * Sets the {@link Schema#unevaluatedItems} property on this annotation.
895       *
896       * @param value The new value for this property.
897       * @return This object.
898       */
899      public Builder unevaluatedItems(String...value) {
900         unevaluatedItems = value;
901         return this;
902      }
903
904      /**
905       * Sets the {@link Schema#unevaluatedProperties} property on this annotation.
906       *
907       * @param value The new value for this property.
908       * @return This object.
909       */
910      public Builder unevaluatedProperties(String...value) {
911         unevaluatedProperties = value;
912         return this;
913      }
914
915      /**
916       * Sets the {@link Schema#uniqueItems} property on this annotation.
917       *
918       * @param value The new value for this property.
919       * @return This object.
920       */
921      public Builder uniqueItems(boolean value) {
922         uniqueItems = value;
923         return this;
924      }
925
926      /**
927       * Sets the {@link Schema#xml} property on this annotation.
928       *
929       * @param value The new value for this property.
930       * @return This object.
931       */
932      public Builder xml(String...value) {
933         xml = value;
934         return this;
935      }
936
937      @Override /* Overridden from AppliedAnnotationObject.Builder */
938      public Builder on(String...value) {
939         super.on(value);
940         return this;
941      }
942
943      @Override /* Overridden from AppliedAnnotationObject.BuilderT */
944      public Builder on(Class<?>...value) {
945         super.on(value);
946         return this;
947      }
948
949      @Override /* Overridden from AppliedOnClassAnnotationObject.Builder */
950      public Builder onClass(Class<?>...value) {
951         super.onClass(value);
952         return this;
953      }
954
955      @Override /* Overridden from AppliedAnnotationObject.BuilderM */
956      public Builder on(Method...value) {
957         super.on(value);
958         return this;
959      }
960
961      @Override /* Overridden from AppliedAnnotationObject.BuilderMF */
962      public Builder on(Field...value) {
963         super.on(value);
964         return this;
965      }
966
967      @Override /* Overridden from AppliedAnnotationObject.BuilderT */
968      public Builder on(ClassInfo...value) {
969         super.on(value);
970         return this;
971      }
972
973      @Override /* Overridden from AppliedAnnotationObject.BuilderT */
974      public Builder onClass(ClassInfo...value) {
975         super.onClass(value);
976         return this;
977      }
978
979      @Override /* Overridden from AppliedAnnotationObject.BuilderTMF */
980      public Builder on(FieldInfo...value) {
981         super.on(value);
982         return this;
983      }
984
985      @Override /* Overridden from AppliedAnnotationObject.BuilderTMF */
986      public Builder on(MethodInfo...value) {
987         super.on(value);
988         return this;
989      }
990
991   }
992
993   private static class Object extends AppliedOnClassAnnotationObject implements Schema {
994
995      private final String[] description;
996      private final boolean aev, allowEmptyValue, exclusiveMaximum, emax, exclusiveMinimum, emin, uniqueItems, ui, required, r, readOnly, ro, sie, skipIfEmpty, ignore;
997      private final ExternalDocs externalDocs;
998      private final Items items;
999      private final long maxLength, maxl, minLength, minl, maxItems, maxi, minItems, mini, maxProperties, maxp, minProperties, minp;
1000      private final String $ref, format, f, title, multipleOf, mo, maximum, max, minimum, min, pattern, p, type, t, collectionFormat, cf, discriminator;
1001      private final String[] d, default_, df, enum_, e, allOf, properties, additionalProperties, xml;
1002      // JSON Schema Draft 2020-12 fields
1003      private final boolean deprecatedProperty;
1004      private final String $id, contentMediaType, contentEncoding, exclusiveMaximumValue, exclusiveMinimumValue;
1005      private final String[] const_, examples, $comment, prefixItems, unevaluatedItems, unevaluatedProperties, dependentSchemas, dependentRequired, if_, then_, else_, $defs;
1006
1007      Object(SchemaAnnotation.Builder b) {
1008         super(b);
1009         description = copyOf(b.description);
1010         $ref = b.$ref;
1011         default_ = copyOf(b.default_);
1012         enum_ = copyOf(b.enum_);
1013         additionalProperties = copyOf(b.additionalProperties);
1014         allOf = copyOf(b.allOf);
1015         aev = b.aev;
1016         allowEmptyValue = b.allowEmptyValue;
1017         cf = b.cf;
1018         collectionFormat = b.collectionFormat;
1019         d = copyOf(b.d);
1020         df = copyOf(b.df);
1021         discriminator = b.discriminator;
1022         e = copyOf(b.e);
1023         emax = b.emax;
1024         emin = b.emin;
1025         exclusiveMaximum = b.exclusiveMaximum;
1026         exclusiveMinimum = b.exclusiveMinimum;
1027         externalDocs = b.externalDocs;
1028         f = b.f;
1029         format = b.format;
1030         ignore = b.ignore;
1031         items = b.items;
1032         max = b.max;
1033         maxi = b.maxi;
1034         maximum = b.maximum;
1035         maxItems = b.maxItems;
1036         maxl = b.maxl;
1037         maxLength = b.maxLength;
1038         maxp = b.maxp;
1039         maxProperties = b.maxProperties;
1040         min = b.min;
1041         mini = b.mini;
1042         minimum = b.minimum;
1043         minItems = b.minItems;
1044         minl = b.minl;
1045         minLength = b.minLength;
1046         minp = b.minp;
1047         minProperties = b.minProperties;
1048         mo = b.mo;
1049         multipleOf = b.multipleOf;
1050         p = b.p;
1051         pattern = b.pattern;
1052         properties = copyOf(b.properties);
1053         r = b.r;
1054         readOnly = b.readOnly;
1055         required = b.required;
1056         ro = b.ro;
1057         sie = b.sie;
1058         skipIfEmpty = b.skipIfEmpty;
1059         t = b.t;
1060         title = b.title;
1061         type = b.type;
1062         ui = b.ui;
1063         uniqueItems = b.uniqueItems;
1064         xml = copyOf(b.xml);
1065         deprecatedProperty = b.deprecatedProperty;
1066         $id = b.$id;
1067         contentMediaType = b.contentMediaType;
1068         contentEncoding = b.contentEncoding;
1069         exclusiveMaximumValue = b.exclusiveMaximumValue;
1070         exclusiveMinimumValue = b.exclusiveMinimumValue;
1071         const_ = copyOf(b.const_);
1072         examples = copyOf(b.examples);
1073         $comment = copyOf(b.$comment);
1074         prefixItems = copyOf(b.prefixItems);
1075         unevaluatedItems = copyOf(b.unevaluatedItems);
1076         unevaluatedProperties = copyOf(b.unevaluatedProperties);
1077         dependentSchemas = copyOf(b.dependentSchemas);
1078         dependentRequired = copyOf(b.dependentRequired);
1079         if_ = copyOf(b.if_);
1080         then_ = copyOf(b.then_);
1081         else_ = copyOf(b.else_);
1082         $defs = copyOf(b.$defs);
1083      }
1084
1085      @Override /* Overridden from Schema */
1086      public String[] const_() {
1087         return const_;
1088      }
1089
1090      @Override /* Overridden from Schema */
1091      public String[] default_() {
1092         return default_;
1093      }
1094
1095      @Override /* Overridden from Schema */
1096      public String[] else_() {
1097         return else_;
1098      }
1099
1100      @Override /* Overridden from Schema */
1101      public String[] enum_() {
1102         return enum_;
1103      }
1104
1105      @Override /* Overridden from Schema */
1106      public String[] if_() {
1107         return if_;
1108      }
1109
1110      @Override /* Overridden from Schema */
1111      public String[] then_() {
1112         return then_;
1113      }
1114
1115      @Override /* Overridden from Schema */
1116      public String[] $comment() {
1117         return $comment;
1118      }
1119
1120      @Override /* Overridden from Schema */
1121      public String[] $defs() {
1122         return $defs;
1123      }
1124
1125      @Override /* Overridden from Schema */
1126      public String $id() {
1127         return $id;
1128      }
1129
1130      @Override /* Overridden from Schema */
1131      public String $ref() {
1132         return $ref;
1133      }
1134
1135      @Override /* Overridden from Schema */
1136      public String[] additionalProperties() {
1137         return additionalProperties;
1138      }
1139
1140      @Override /* Overridden from Schema */
1141      public boolean aev() {
1142         return aev;
1143      }
1144
1145      @Override /* Overridden from Schema */
1146      public String[] allOf() {
1147         return allOf;
1148      }
1149
1150      @Override /* Overridden from Schema */
1151      public boolean allowEmptyValue() {
1152         return allowEmptyValue;
1153      }
1154
1155      @Override /* Overridden from Schema */
1156      public String cf() {
1157         return cf;
1158      }
1159
1160      @Override /* Overridden from Schema */
1161      public String collectionFormat() {
1162         return collectionFormat;
1163      }
1164
1165      @Override /* Overridden from Schema */
1166      public String contentEncoding() {
1167         return contentEncoding;
1168      }
1169
1170      @Override /* Overridden from Schema */
1171      public String contentMediaType() {
1172         return contentMediaType;
1173      }
1174
1175      @Override /* Overridden from Schema */
1176      public String[] d() {
1177         return d;
1178      }
1179
1180      @Override /* Overridden from Schema */
1181      public String[] dependentRequired() {
1182         return dependentRequired;
1183      }
1184
1185      @Override /* Overridden from Schema */
1186      public String[] dependentSchemas() {
1187         return dependentSchemas;
1188      }
1189
1190      @Override /* Overridden from Schema */
1191      public boolean deprecatedProperty() {
1192         return deprecatedProperty;
1193      }
1194
1195      @Override /* Overridden from Schema */
1196      public String[] df() {
1197         return df;
1198      }
1199
1200      @Override /* Overridden from Schema */
1201      public String discriminator() {
1202         return discriminator;
1203      }
1204
1205      @Override /* Overridden from Schema */
1206      public String[] e() {
1207         return e;
1208      }
1209
1210      @Override /* Overridden from Schema */
1211      public boolean emax() {
1212         return emax;
1213      }
1214
1215      @Override /* Overridden from Schema */
1216      public boolean emin() {
1217         return emin;
1218      }
1219
1220      @Override /* Overridden from Schema */
1221      public String[] examples() {
1222         return examples;
1223      }
1224
1225      @Override /* Overridden from Schema */
1226      public boolean exclusiveMaximum() {
1227         return exclusiveMaximum;
1228      }
1229
1230      @Override /* Overridden from Schema */
1231      public String exclusiveMaximumValue() {
1232         return exclusiveMaximumValue;
1233      }
1234
1235      @Override /* Overridden from Schema */
1236      public boolean exclusiveMinimum() {
1237         return exclusiveMinimum;
1238      }
1239
1240      @Override /* Overridden from Schema */
1241      public String exclusiveMinimumValue() {
1242         return exclusiveMinimumValue;
1243      }
1244
1245      @Override /* Overridden from Schema */
1246      public ExternalDocs externalDocs() {
1247         return externalDocs;
1248      }
1249
1250      @Override /* Overridden from Schema */
1251      public String f() {
1252         return f;
1253      }
1254
1255      @Override /* Overridden from Schema */
1256      public String format() {
1257         return format;
1258      }
1259
1260      @Override /* Overridden from Schema */
1261      public boolean ignore() {
1262         return ignore;
1263      }
1264
1265      @Override /* Overridden from Schema */
1266      public Items items() {
1267         return items;
1268      }
1269
1270      @Override /* Overridden from Schema */
1271      public String max() {
1272         return max;
1273      }
1274
1275      @Override /* Overridden from Schema */
1276      public long maxi() {
1277         return maxi;
1278      }
1279
1280      @Override /* Overridden from Schema */
1281      public String maximum() {
1282         return maximum;
1283      }
1284
1285      @Override /* Overridden from Schema */
1286      public long maxItems() {
1287         return maxItems;
1288      }
1289
1290      @Override /* Overridden from Schema */
1291      public long maxl() {
1292         return maxl;
1293      }
1294
1295      @Override /* Overridden from Schema */
1296      public long maxLength() {
1297         return maxLength;
1298      }
1299
1300      @Override /* Overridden from Schema */
1301      public long maxp() {
1302         return maxp;
1303      }
1304
1305      @Override /* Overridden from Schema */
1306      public long maxProperties() {
1307         return maxProperties;
1308      }
1309
1310      @Override /* Overridden from Schema */
1311      public String min() {
1312         return min;
1313      }
1314
1315      @Override /* Overridden from Schema */
1316      public long mini() {
1317         return mini;
1318      }
1319
1320      @Override /* Overridden from Schema */
1321      public String minimum() {
1322         return minimum;
1323      }
1324
1325      @Override /* Overridden from Schema */
1326      public long minItems() {
1327         return minItems;
1328      }
1329
1330      @Override /* Overridden from Schema */
1331      public long minl() {
1332         return minl;
1333      }
1334
1335      @Override /* Overridden from Schema */
1336      public long minLength() {
1337         return minLength;
1338      }
1339
1340      @Override /* Overridden from Schema */
1341      public long minp() {
1342         return minp;
1343      }
1344
1345      @Override /* Overridden from Schema */
1346      public long minProperties() {
1347         return minProperties;
1348      }
1349
1350      @Override /* Overridden from Schema */
1351      public String mo() {
1352         return mo;
1353      }
1354
1355      @Override /* Overridden from Schema */
1356      public String multipleOf() {
1357         return multipleOf;
1358      }
1359
1360      // -----------------------------------------------------------------------------------------------------------------
1361      // JSON Schema Draft 2020-12 property getters
1362      // -----------------------------------------------------------------------------------------------------------------
1363
1364      @Override /* Overridden from Schema */
1365      public String p() {
1366         return p;
1367      }
1368
1369      @Override /* Overridden from Schema */
1370      public String pattern() {
1371         return pattern;
1372      }
1373
1374      @Override /* Overridden from Schema */
1375      public String[] prefixItems() {
1376         return prefixItems;
1377      }
1378
1379      @Override /* Overridden from Schema */
1380      public String[] properties() {
1381         return properties;
1382      }
1383
1384      @Override /* Overridden from Schema */
1385      public boolean r() {
1386         return r;
1387      }
1388
1389      @Override /* Overridden from Schema */
1390      public boolean readOnly() {
1391         return readOnly;
1392      }
1393
1394      @Override /* Overridden from Schema */
1395      public boolean required() {
1396         return required;
1397      }
1398
1399      @Override /* Overridden from Schema */
1400      public boolean ro() {
1401         return ro;
1402      }
1403
1404      @Override /* Overridden from Schema */
1405      public boolean sie() {
1406         return sie;
1407      }
1408
1409      @Override /* Overridden from Schema */
1410      public boolean skipIfEmpty() {
1411         return skipIfEmpty;
1412      }
1413
1414      @Override /* Overridden from Schema */
1415      public String t() {
1416         return t;
1417      }
1418
1419      @Override /* Overridden from Schema */
1420      public String title() {
1421         return title;
1422      }
1423
1424      @Override /* Overridden from Schema */
1425      public String type() {
1426         return type;
1427      }
1428
1429      @Override /* Overridden from Schema */
1430      public boolean ui() {
1431         return ui;
1432      }
1433
1434      @Override /* Overridden from Schema */
1435      public String[] unevaluatedItems() {
1436         return unevaluatedItems;
1437      }
1438
1439      @Override /* Overridden from Schema */
1440      public String[] unevaluatedProperties() {
1441         return unevaluatedProperties;
1442      }
1443
1444      @Override /* Overridden from Schema */
1445      public boolean uniqueItems() {
1446         return uniqueItems;
1447      }
1448
1449      @Override /* Overridden from Schema */
1450      public String[] xml() {
1451         return xml;
1452      }
1453
1454      @Override /* Overridden from annotation */
1455      public String[] description() {
1456         return description;
1457      }
1458   }
1459
1460   /** Default value */
1461   public static final Schema DEFAULT = create().build();
1462
1463   /**
1464    * Converts the specified <ja>@Schema</ja> annotation into a generic map.
1465    *
1466    * @param a The annotation instance.  Can be <jk>null</jk>.
1467    * @return The schema converted to a map, or and empty map if the annotation was null.
1468    * @throws ParseException Malformed input encountered.
1469    */
1470   @SuppressWarnings("deprecation")
1471   public static JsonMap asMap(Schema a) throws ParseException {
1472      if (a == null)
1473         return JsonMap.EMPTY_MAP;
1474      var m = new JsonMap();
1475      if (SchemaAnnotation.empty(a))
1476         return m;
1477      Predicate<String> ne = Utils::ne;
1478      Predicate<Collection<?>> nec = Utils::ne;
1479      Predicate<Map<?,?>> nem = Utils::ne;
1480      Predicate<Boolean> nf = Utils::isTrue;
1481      Predicate<Long> nm1 = Utils::nm1;
1482      // @formatter:off
1483      return m
1484         .appendIf(nem, "additionalProperties", parseMap(a.additionalProperties()))
1485         .appendIf(ne, "allOf", joinnl(a.allOf()))
1486         .appendFirst(ne, "collectionFormat", a.collectionFormat(), a.cf())
1487         .appendIf(ne, "default", joinnl(a.default_(), a.df()))
1488         .appendIf(ne, "discriminator", a.discriminator())
1489         .appendIf(ne, "description", joinnl(a.description(), a.d()))
1490         .appendFirst(nec, "enum", parseSet(a.enum_()), parseSet(a.e()))
1491         // Handle exclusiveMaximum with Draft 2020-12 fallback
1492         .appendIf(ne, "exclusiveMaximum",
1493            ne.test(a.exclusiveMaximumValue()) ? a.exclusiveMaximumValue() :
1494            (a.exclusiveMaximum() || a.emax()) ? "true" : null)
1495         // Handle exclusiveMinimum with Draft 2020-12 fallback
1496         .appendIf(ne, "exclusiveMinimum",
1497            ne.test(a.exclusiveMinimumValue()) ? a.exclusiveMinimumValue() :
1498            (a.exclusiveMinimum() || a.emin()) ? "true" : null)
1499         .appendIf(nem, "externalDocs", ExternalDocsAnnotation.merge(m.getMap("externalDocs"), a.externalDocs()))
1500         .appendFirst(ne, "format", a.format(), a.f())
1501         .appendIf(ne, "ignore", a.ignore() ? "true" : null)
1502         .appendIf(nem, "items", merge(m.getMap("items"), a.items()))
1503         .appendFirst(ne, "maximum", a.maximum(), a.max())
1504         .appendFirst(nm1, "maxItems", a.maxItems(), a.maxi())
1505         .appendFirst(nm1, "maxLength", a.maxLength(), a.maxl())
1506         .appendFirst(nm1, "maxProperties", a.maxProperties(), a.maxp())
1507         .appendFirst(ne, "minimum", a.minimum(), a.min())
1508         .appendFirst(nm1, "minItems", a.minItems(), a.mini())
1509         .appendFirst(nm1, "minLength", a.minLength(), a.minl())
1510         .appendFirst(nm1, "minProperties", a.minProperties(), a.minp())
1511         .appendFirst(ne, "multipleOf", a.multipleOf(), a.mo())
1512         .appendFirst(ne, "pattern", a.pattern(), a.p())
1513         .appendIf(nem, "properties", parseMap(a.properties()))
1514         .appendIf(nf, "readOnly", a.readOnly() || a.ro())
1515         .appendIf(nf, "required", a.required() || a.r())
1516         .appendIf(ne, "title", a.title())
1517         .appendFirst(ne, "type", a.type(), a.t())
1518         .appendIf(nf, "uniqueItems", a.uniqueItems() || a.ui())
1519         .appendIf(ne, "xml", joinnl(a.xml()))
1520         .appendIf(ne, "$ref", a.$ref())
1521         // JSON Schema Draft 2020-12 properties
1522         .appendIf(ne, "const", joinnl(a.const_()))
1523         .appendIf(nec, "examples", a.examples().length == 0 ? null : l(a.examples()))
1524         .appendIf(ne, "$comment", joinnl(a.$comment()))
1525         .appendIf(nf, "deprecated", a.deprecatedProperty())
1526         .appendIf(ne, "contentMediaType", a.contentMediaType())
1527         .appendIf(ne, "contentEncoding", a.contentEncoding())
1528         .appendIf(ne, "prefixItems", joinnl(a.prefixItems()))
1529         .appendIf(ne, "unevaluatedItems", joinnl(a.unevaluatedItems()))
1530         .appendIf(ne, "unevaluatedProperties", joinnl(a.unevaluatedProperties()))
1531         .appendIf(ne, "dependentSchemas", joinnl(a.dependentSchemas()))
1532         .appendIf(ne, "dependentRequired", joinnl(a.dependentRequired()))
1533         .appendIf(ne, "if", joinnl(a.if_()))
1534         .appendIf(ne, "then", joinnl(a.then_()))
1535         .appendIf(ne, "else", joinnl(a.else_()))
1536         .appendIf(ne, "$defs", joinnl(a.$defs()))
1537         .appendIf(ne, "$id", a.$id())
1538      ;
1539      // @formatter:on
1540   }
1541
1542   /**
1543    * Instantiates a new builder for this class.
1544    *
1545    * @return A new builder object.
1546    */
1547   public static Builder create() {
1548      return new Builder();
1549   }
1550
1551   /**
1552    * Instantiates a new builder for this class.
1553    *
1554    * @param on The targets this annotation applies to.
1555    * @return A new builder object.
1556    */
1557   public static Builder create(Class<?>...on) {
1558      return create().on(on);
1559   }
1560
1561   /**
1562    * Instantiates a new builder for this class.
1563    *
1564    * @param on The targets this annotation applies to.
1565    * @return A new builder object.
1566    */
1567   public static Builder create(String...on) {
1568      return create().on(on);
1569   }
1570
1571   /**
1572    * Returns <jk>true</jk> if the specified annotation contains all default values.
1573    *
1574    * @param a The annotation to check.
1575    * @return <jk>true</jk> if the specified annotation contains all default values.
1576    */
1577   public static boolean empty(Schema a) {
1578      return a == null || DEFAULT.equals(a);
1579   }
1580
1581   private static JsonMap merge(JsonMap m, Items a) throws ParseException {
1582      if (ItemsAnnotation.empty(a))
1583         return m;
1584      Predicate<String> ne = Utils::ne;
1585      Predicate<Collection<?>> nec = Utils::ne;
1586      Predicate<Map<?,?>> nem = Utils::ne;
1587      Predicate<Boolean> nf = Utils::isTrue;
1588      Predicate<Long> nm1 = Utils::nm1;
1589      return m.appendFirst(ne, "collectionFormat", a.collectionFormat(), a.cf()).appendIf(ne, "default", joinnl(a.default_(), a.df())).appendFirst(nec, "enum", parseSet(a.enum_()), parseSet(a.e()))
1590         .appendFirst(ne, "format", a.format(), a.f()).appendIf(nf, "exclusiveMaximum", a.exclusiveMaximum() || a.emax()).appendIf(nf, "exclusiveMinimum", a.exclusiveMinimum() || a.emin())
1591         .appendIf(nem, "items", SubItemsAnnotation.merge(m.getMap("items"), a.items())).appendFirst(ne, "maximum", a.maximum(), a.max()).appendFirst(nm1, "maxItems", a.maxItems(), a.maxi())
1592         .appendFirst(nm1, "maxLength", a.maxLength(), a.maxl()).appendFirst(ne, "minimum", a.minimum(), a.min()).appendFirst(nm1, "minItems", a.minItems(), a.mini())
1593         .appendFirst(nm1, "minLength", a.minLength(), a.minl()).appendFirst(ne, "multipleOf", a.multipleOf(), a.mo()).appendFirst(ne, "pattern", a.pattern(), a.p())
1594         .appendIf(nf, "uniqueItems", a.uniqueItems() || a.ui()).appendFirst(ne, "type", a.type(), a.t()).appendIf(ne, "$ref", a.$ref());
1595   }
1596}