001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.httppart;
014
015import static java.util.Collections.*;
016import static org.apache.juneau.common.internal.StringUtils.*;
017import static org.apache.juneau.common.internal.ThrowableUtils.*;
018import static org.apache.juneau.httppart.HttpPartDataType.*;
019import static org.apache.juneau.httppart.HttpPartFormat.*;
020import static org.apache.juneau.internal.ClassUtils.*;
021import static org.apache.juneau.internal.CollectionUtils.*;
022
023import java.lang.annotation.*;
024import java.lang.reflect.*;
025import java.math.*;
026import java.util.*;
027import java.util.concurrent.atomic.*;
028import java.util.function.*;
029import java.util.regex.*;
030
031import org.apache.juneau.*;
032import org.apache.juneau.annotation.*;
033import org.apache.juneau.collections.*;
034import org.apache.juneau.common.internal.*;
035import org.apache.juneau.http.annotation.*;
036import org.apache.juneau.internal.*;
037import org.apache.juneau.parser.*;
038import org.apache.juneau.reflect.*;
039
040/**
041 * Represents an OpenAPI schema definition.
042 *
043 * <p>
044 * The schema definition can be applied to any HTTP parts such as bodies, headers, query/form parameters, and URL path parts.
045 * <br>The API is generic enough to apply to any path part although some attributes may only applicable for certain parts.
046 *
047 * <p>
048 * Schema objects are created via builders instantiated through the {@link #create()} method.
049 *
050 * <h5 class='section'>Notes:</h5><ul>
051 *    <li class='note'>This class is thread safe and reusable.
052 * </ul>
053 *
054 * <h5 class='section'>See Also:</h5><ul>
055 *    <li class='link'><a class="doclink" href="../../../../index.html#jm.OpenApiDetails">OpenAPI Details</a>
056 * </ul>
057 */
058public class HttpPartSchema {
059
060   //-------------------------------------------------------------------------------------------------------------------
061   // Static
062   //-------------------------------------------------------------------------------------------------------------------
063
064   /** Reusable instance of this object, all default settings. */
065   public static final HttpPartSchema DEFAULT = HttpPartSchema.create().allowEmptyValue(true).build();
066
067   /** Boolean type */
068   public static final HttpPartSchema T_BOOLEAN = HttpPartSchema.tBoolean().build();
069
070   /** File type */
071   public static final HttpPartSchema T_FILE = HttpPartSchema.tFile().build();
072
073   /** Integer type */
074   public static final HttpPartSchema T_INTEGER = HttpPartSchema.tInteger().build();
075
076   /** Int32 type */
077   public static final HttpPartSchema T_INT32 = HttpPartSchema.tInt32().build();
078
079   /** Int64 type */
080   public static final HttpPartSchema T_INT64 = HttpPartSchema.tInt64().build();
081
082   /** No type */
083   public static final HttpPartSchema T_NONE = HttpPartSchema.tNone().build();
084
085   /** Number type */
086   public static final HttpPartSchema T_NUMBER = HttpPartSchema.tNumber().build();
087
088   /** Float type */
089   public static final HttpPartSchema T_FLOAT = HttpPartSchema.tFloat().build();
090
091   /** Double type */
092   public static final HttpPartSchema T_DOUBLE = HttpPartSchema.tDouble().build();
093
094   /** String type */
095   public static final HttpPartSchema T_STRING = HttpPartSchema.tString().build();
096
097   /** Byte type */
098   public static final HttpPartSchema T_BYTE = HttpPartSchema.tByte().build();
099
100   /** Binary type */
101   public static final HttpPartSchema T_BINARY = HttpPartSchema.tBinary().build();
102
103   /** Spaced binary type */
104   public static final HttpPartSchema T_BINARY_SPACED = HttpPartSchema.tBinarySpaced().build();
105
106   /** Date type */
107   public static final HttpPartSchema T_DATE = HttpPartSchema.tDate().build();
108
109   /** Date-time type */
110   public static final HttpPartSchema T_DATETIME = HttpPartSchema.tDateTime().build();
111
112   /** UON-formated simple type */
113   public static final HttpPartSchema T_UON = HttpPartSchema.tUon().build();
114
115   /** Array type */
116   public static final HttpPartSchema T_ARRAY = HttpPartSchema.tArray().build();
117
118   /** Comma-delimited array type */
119   public static final HttpPartSchema T_ARRAY_CSV = HttpPartSchema.tArrayCsv().build();
120
121   /** Pipe-delimited array type */
122   public static final HttpPartSchema T_ARRAY_PIPES = HttpPartSchema.tArrayPipes().build();
123
124   /** Space-delimited array type */
125   public static final HttpPartSchema T_ARRAY_SSV = HttpPartSchema.tArraySsv().build();
126
127   /** Tab-delimited array type */
128   public static final HttpPartSchema T_ARRAY_TSV = HttpPartSchema.tArrayTsv().build();
129
130   /** UON-formatted array type */
131   public static final HttpPartSchema T_ARRAY_UON = HttpPartSchema.tArrayUon().build();
132
133   /** Multi-part array type */
134   public static final HttpPartSchema T_ARRAY_MULTI = HttpPartSchema.tArrayMulti().build();
135
136   /** Object type */
137   public static final HttpPartSchema T_OBJECT = HttpPartSchema.tObject().build();
138
139   /** Comma-delimited object type */
140   public static final HttpPartSchema T_OBJECT_CSV = HttpPartSchema.tObjectCsv().build();
141
142   /** Pipe-delimited object type */
143   public static final HttpPartSchema T_OBJECT_PIPES = HttpPartSchema.tObjectPipes().build();
144
145   /** Space-delimited object type */
146   public static final HttpPartSchema T_OBJECT_SSV = HttpPartSchema.tObjectSsv().build();
147
148   /** Tab-delimited object type */
149   public static final HttpPartSchema T_OBJECT_TSV = HttpPartSchema.tObjectTsv().build();
150
151   /** UON-formated object type */
152   public static final HttpPartSchema T_OBJECT_UON = HttpPartSchema.tObjectUon().build();
153
154   /**
155    * Instantiates a new builder for this object.
156    *
157    * @return A new builder for this object.
158    */
159   public static Builder create() {
160      return new Builder();
161   }
162
163   /**
164    * Shortcut for <c><jsm>create</jsm>().type(HttpPartDataType.<jsf>BOOLEAN</jsf>)</c>.
165    *
166    * @return A new builder for this object.
167    */
168   public static Builder tBoolean() {
169      return create().tBoolean();
170   }
171
172   /**
173    * Shortcut for <c><jsm>create</jsm>().type(HttpPartDataType.<jsf>FILE</jsf>)</c>.
174    *
175    * @return A new builder for this object.
176    */
177   public static Builder tFile() {
178      return create().tFile();
179   }
180
181   /**
182    * Shortcut for <c><jsm>create</jsm>().type(HttpPartDataType.<jsf>INTEGER</jsf>)</c>.
183    *
184    * @return A new builder for this object.
185    */
186   public static Builder tInteger() {
187      return create().tInteger();
188   }
189
190   /**
191    * Shortcut for <c><jsm>create</jsm>().type(HttpPartDataType.<jsf>INTEGER</jsf>).format(HttpPartFormat.<jsf>INT32</jsf>)</c>.
192    *
193    * @return A new builder for this object.
194    */
195   public static Builder tInt32() {
196      return create().tInteger().fInt32();
197   }
198
199   /**
200    * Shortcut for <c><jsm>create</jsm>().type(HttpPartDataType.<jsf>INTEGER</jsf>).format(HttpPartFormat.<jsf>INT64</jsf>)</c>.
201    *
202    * @return A new builder for this object.
203    */
204   public static Builder tInt64() {
205      return create().tInteger().fInt64();
206   }
207
208   /**
209    * Shortcut for <c><jsm>create</jsm>().type(HttpPartDataType.<jsf>NONE</jsf>)</c>.
210    *
211    * @return A new builder for this object.
212    */
213   public static Builder tNone() {
214      return create().tNone();
215   }
216
217   /**
218    * Shortcut for <c><jsm>create</jsm>().type(HttpPartDataType.<jsf>NUMBER</jsf>)</c>.
219    *
220    * @return A new builder for this object.
221    */
222   public static Builder tNumber() {
223      return create().tNumber();
224   }
225
226   /**
227    * Shortcut for <c><jsm>create</jsm>().type(HttpPartDataType.<jsf>NUMBER</jsf>).format(HttpPartFormat.<jsf>FLOAT</jsf>)</c>.
228    *
229    * @return A new builder for this object.
230    */
231   public static Builder tFloat() {
232      return create().tNumber().fFloat();
233   }
234
235   /**
236    * Shortcut for <c><jsm>create</jsm>().type(HttpPartDataType.<jsf>NUMBER</jsf>).format(HttpPartFormat.<jsf>DOUBLE</jsf>)</c>.
237    *
238    * @return A new builder for this object.
239    */
240   public static Builder tDouble() {
241      return create().tNumber().fDouble();
242   }
243
244   /**
245    * Shortcut for <c><jsm>create</jsm>().type(HttpPartDataType.<jsf>STRING</jsf>)</c>.
246    *
247    * @return A new builder for this object.
248    */
249   public static Builder tString() {
250      return create().tString();
251   }
252
253   /**
254    * Shortcut for <c><jsm>create</jsm>().type(HttpPartDataType.<jsf>STRING</jsf>).format(HttpPartFormat.<jsf>BYTE</jsf>)</c>.
255    *
256    * @return A new builder for this object.
257    */
258   public static Builder tByte() {
259      return create().tString().fByte();
260   }
261
262   /**
263    * Shortcut for <c><jsm>create</jsm>().type(HttpPartDataType.<jsf>STRING</jsf>).format(HttpPartFormat.<jsf>BINARY</jsf>)</c>.
264    *
265    * @return A new builder for this object.
266    */
267   public static Builder tBinary() {
268      return create().tString().fBinary();
269   }
270
271   /**
272    * Shortcut for <c><jsm>create</jsm>().type(HttpPartDataType.<jsf>STRING</jsf>).format(HttpPartFormat.<jsf>BINARY_SPACED</jsf>)</c>.
273    *
274    * @return A new builder for this object.
275    */
276   public static Builder tBinarySpaced() {
277      return create().tString().fBinarySpaced();
278   }
279
280   /**
281    * Shortcut for <c><jsm>create</jsm>().type(HttpPartDataType.<jsf>STRING</jsf>).format(HttpPartFormat.<jsf>DATE</jsf>)</c>.
282    *
283    * @return A new builder for this object.
284    */
285   public static Builder tDate() {
286      return create().tString().fDate();
287   }
288
289   /**
290    * Shortcut for <c><jsm>create</jsm>().type(HttpPartDataType.<jsf>STRING</jsf>).format(HttpPartFormat.<jsf>DATE_TIME</jsf>)</c>.
291    *
292    * @return A new builder for this object.
293    */
294   public static Builder tDateTime() {
295      return create().tString().fDateTime();
296   }
297
298   /**
299    * Shortcut for <c><jsm>create</jsm>().type(HttpPartDataType.<jsf>STRING</jsf>).format(HttpPartFormat.<jsf>UON</jsf>)</c>.
300    *
301    * @return A new builder for this object.
302    */
303   public static Builder tUon() {
304      return create().tString().fUon();
305   }
306
307   /**
308    * Shortcut for <c><jsm>create</jsm>().type(HttpPartDataType.<jsf>ARRAY</jsf>)</c>.
309    *
310    * @return A new builder for this object.
311    */
312   public static Builder tArray() {
313      return create().tArray();
314   }
315
316   /**
317    * Shortcut for <c><jsm>create</jsm>().type(HttpPartDataType.<jsf>ARRAY</jsf>).items(items)</c>.
318    *
319    * @param items The schema of the array items.
320    * @return A new builder for this object.
321    */
322   public static Builder tArray(Builder items) {
323      return create().tArray().items(items);
324   }
325
326   /**
327    * Shortcut for <c><jsm>create</jsm>().type(HttpPartDataType.<jsf>ARRAY</jsf>).collectionFormat(HttpPartCollectionFormat.<jsf>CSV</jsf>)</c>.
328    *
329    * @return A new builder for this object.
330    */
331   public static Builder tArrayCsv() {
332      return create().tArray().cfCsv();
333   }
334
335   /**
336    * Shortcut for <c><jsm>create</jsm>().type(HttpPartDataType.<jsf>ARRAY</jsf>).collectionFormat(HttpPartCollectionFormat.<jsf>CSV</jsf>).items(items)</c>.
337    *
338    * @param items The schema of the array items.
339    * @return A new builder for this object.
340    */
341   public static Builder tArrayCsv(Builder items) {
342      return create().tArray().cfCsv().items(items);
343   }
344
345   /**
346    * Shortcut for <c><jsm>create</jsm>().type(HttpPartDataType.<jsf>ARRAY</jsf>).collectionFormat(HttpPartCollectionFormat.<jsf>PIPES</jsf>)</c>.
347    *
348    * @return A new builder for this object.
349    */
350   public static Builder tArrayPipes() {
351      return create().tArray().cfPipes();
352   }
353
354   /**
355    * Shortcut for <c><jsm>create</jsm>().type(HttpPartDataType.<jsf>ARRAY</jsf>).collectionFormat(HttpPartCollectionFormat.<jsf>PIPES</jsf>).items(items)</c>.
356    *
357    * @param items The schema of the array items.
358    * @return A new builder for this object.
359    */
360   public static Builder tArrayPipes(Builder items) {
361      return create().tArray().cfPipes().items(items);
362   }
363
364   /**
365    * Shortcut for <c><jsm>create</jsm>().type(HttpPartDataType.<jsf>ARRAY</jsf>).collectionFormat(HttpPartCollectionFormat.<jsf>SSV</jsf>)</c>.
366    *
367    * @return A new builder for this object.
368    */
369   public static Builder tArraySsv() {
370      return create().tArray().cfSsv();
371   }
372
373   /**
374    * Shortcut for <c><jsm>create</jsm>().type(HttpPartDataType.<jsf>ARRAY</jsf>).collectionFormat(HttpPartCollectionFormat.<jsf>SSV</jsf>).items(items)</c>.
375    *
376    * @param items The schema of the array items.
377    * @return A new builder for this object.
378    */
379   public static Builder tArraySsv(Builder items) {
380      return create().tArray().cfSsv().items(items);
381   }
382
383   /**
384    * Shortcut for <c><jsm>create</jsm>().type(HttpPartDataType.<jsf>ARRAY</jsf>).collectionFormat(HttpPartCollectionFormat.<jsf>TSV</jsf>)</c>.
385    *
386    * @return A new builder for this object.
387    */
388   public static Builder tArrayTsv() {
389      return create().tArray().cfTsv();
390   }
391
392   /**
393    * Shortcut for <c><jsm>create</jsm>().type(HttpPartDataType.<jsf>ARRAY</jsf>).collectionFormat(HttpPartCollectionFormat.<jsf>TSV</jsf>).items(items)</c>.
394    *
395    * @param items The schema of the array items.
396    * @return A new builder for this object.
397    */
398   public static Builder tArrayTsv(Builder items) {
399      return create().tArray().cfTsv().items(items);
400   }
401
402   /**
403    * Shortcut for <c><jsm>create</jsm>().type(HttpPartDataType.<jsf>ARRAY</jsf>).collectionFormat(HttpPartCollectionFormat.<jsf>UONC</jsf>)</c>.
404    *
405    * @return A new builder for this object.
406    */
407   public static Builder tArrayUon() {
408      return create().tArray().cfUon();
409   }
410
411   /**
412    * Shortcut for <c><jsm>create</jsm>().type(HttpPartDataType.<jsf>ARRAY</jsf>).collectionFormat(HttpPartCollectionFormat.<jsf>UONC</jsf>).items(items)</c>.
413    *
414    * @param items The schema of the array items.
415    * @return A new builder for this object.
416    */
417   public static Builder tArrayUon(Builder items) {
418      return create().tArray().cfUon().items(items);
419   }
420
421   /**
422    * Shortcut for <c><jsm>create</jsm>().type(HttpPartDataType.<jsf>ARRAY</jsf>).collectionFormat(HttpPartCollectionFormat.<jsf>MULTI</jsf>)</c>.
423    *
424    * @return A new builder for this object.
425    */
426   public static Builder tArrayMulti() {
427      return create().tArray().cfMulti();
428   }
429
430   /**
431    * Shortcut for <c><jsm>create</jsm>().type(HttpPartDataType.<jsf>ARRAY</jsf>).collectionFormat(HttpPartCollectionFormat.<jsf>MULTI</jsf>).items(items)</c>.
432    *
433    * @param items The schema of the array items.
434    * @return A new builder for this object.
435    */
436   public static Builder tArrayMulti(Builder items) {
437      return create().tArray().cfMulti().items(items);
438   }
439
440   /**
441    * Shortcut for <c><jsm>create</jsm>().type(HttpPartDataType.<jsf>OBJECT</jsf>)</c>.
442    *
443    * @return A new builder for this object.
444    */
445   public static Builder tObject() {
446      return create().tObject();
447   }
448
449   /**
450    * Shortcut for <c><jsm>create</jsm>().type(HttpPartDataType.<jsf>OBJECT</jsf>).collectionFormat(HttpPartCollectionFormat.<jsf>CSV</jsf>)</c>.
451    *
452    * @return A new builder for this object.
453    */
454   public static Builder tObjectCsv() {
455      return create().tObject().cfCsv();
456   }
457
458   /**
459    * Shortcut for <c><jsm>create</jsm>().type(HttpPartDataType.<jsf>OBJECT</jsf>).collectionFormat(HttpPartCollectionFormat.<jsf>PIPES</jsf>)</c>.
460    *
461    * @return A new builder for this object.
462    */
463   public static Builder tObjectPipes() {
464      return create().tObject().cfPipes();
465   }
466
467   /**
468    * Shortcut for <c><jsm>create</jsm>().type(HttpPartDataType.<jsf>OBJECT</jsf>).collectionFormat(HttpPartCollectionFormat.<jsf>SSV</jsf>)</c>.
469    *
470    * @return A new builder for this object.
471    */
472   public static Builder tObjectSsv() {
473      return create().tObject().cfSsv();
474   }
475
476   /**
477    * Shortcut for <c><jsm>create</jsm>().type(HttpPartDataType.<jsf>OBJECT</jsf>).collectionFormat(HttpPartCollectionFormat.<jsf>TSV</jsf>)</c>.
478    *
479    * @return A new builder for this object.
480    */
481   public static Builder tObjectTsv() {
482      return create().tObject().cfTsv();
483   }
484
485   /**
486    * Shortcut for <c><jsm>create</jsm>().type(HttpPartDataType.<jsf>OBJECT</jsf>).collectionFormat(HttpPartCollectionFormat.<jsf>UON</jsf>)</c>.
487    *
488    * @return A new builder for this object.
489    */
490   public static Builder tObjectUon() {
491      return create().tObject().cfUon();
492   }
493
494   /**
495    * Finds the schema information for the specified method parameter.
496    *
497    * <p>
498    * This method will gather all the schema information from the annotations at the following locations:
499    * <ul>
500    *    <li>The method parameter.
501    *    <li>The method parameter class.
502    *    <li>The method parameter parent classes and interfaces.
503    * </ul>
504    *
505    * @param c
506    *    The annotation to look for.
507    *    <br>Valid values:
508    *    <ul>
509    *       <li>{@link Content}
510    *       <li>{@link Header}
511    *       <li>{@link Query}
512    *       <li>{@link FormData}
513    *       <li>{@link Path}
514    *       <li>{@link Response}
515    *       <li>{@link HasQuery}
516    *       <li>{@link HasFormData}
517    *    </ul>
518    * @param mpi The Java method parameter.
519    * @return The schema information about the parameter.
520    */
521   public static HttpPartSchema create(Class<? extends Annotation> c, ParamInfo mpi) {
522      return create().applyAll(c, mpi).build();
523   }
524
525   /**
526    * Finds the schema information for the specified method return.
527    *
528    * <p>
529    * This method will gather all the schema information from the annotations at the following locations:
530    * <ul>
531    *    <li>The method.
532    *    <li>The method return class.
533    *    <li>The method return parent classes and interfaces.
534    * </ul>
535    *
536    * @param c
537    *    The annotation to look for.
538    *    <br>Valid values:
539    *    <ul>
540    *       <li>{@link Content}
541    *       <li>{@link Header}
542    *       <li>{@link Query}
543    *       <li>{@link FormData}
544    *       <li>{@link Path}
545    *       <li>{@link Response}
546    *       <li>{@link HasQuery}
547    *       <li>{@link HasFormData}
548    *    </ul>
549    * @param m
550    *    The Java method with the return type being checked.
551    * @return The schema information about the parameter.
552    */
553   public static HttpPartSchema create(Class<? extends Annotation> c, Method m) {
554      return create().applyAll(c, m).build();
555   }
556
557   /**
558    * Finds the schema information for the specified class.
559    *
560    * <p>
561    * This method will gather all the schema information from the annotations on the class and all parent classes/interfaces.
562    *
563    * @param c
564    *    The annotation to look for.
565    *    <br>Valid values:
566    *    <ul>
567    *       <li>{@link Content}
568    *       <li>{@link Header}
569    *       <li>{@link Query}
570    *       <li>{@link FormData}
571    *       <li>{@link Path}
572    *       <li>{@link Response}
573    *       <li>{@link HasQuery}
574    *       <li>{@link HasFormData}
575    *    </ul>
576    * @param t
577    *    The class containing the parameter.
578    * @return The schema information about the parameter.
579    */
580   public static HttpPartSchema create(Class<? extends Annotation> c, java.lang.reflect.Type t) {
581      return create().applyAll(c, t).build();
582   }
583
584   /**
585    * Shortcut for calling <c>create().type(type);</c>
586    *
587    * @param type The schema type value.
588    * @return A new builder.
589    */
590   public static Builder create(String type) {
591      return create().type(type);
592   }
593
594   /**
595    * Shortcut for calling <c>create().type(type).format(format);</c>
596    *
597    * @param type The schema type value.
598    * @param format The schema format value.
599    * @return A new builder.
600    */
601   public static Builder create(String type, String format) {
602      return create().type(type).format(format);
603   }
604
605   /**
606    * Finds the schema information on the specified annotation.
607    *
608    * @param a
609    *    The annotation to find the schema information on..
610    * @return The schema information found on the annotation.
611    */
612   public static HttpPartSchema create(Annotation a) {
613      return create().apply(a).build();
614   }
615
616   /**
617    * Finds the schema information on the specified annotation.
618    *
619    * @param a
620    *    The annotation to find the schema information on..
621    * @param defaultName The default part name if not specified on the annotation.
622    * @return The schema information found on the annotation.
623    */
624   public static HttpPartSchema create(Annotation a, String defaultName) {
625      return create().name(defaultName).apply(a).build();
626   }
627
628   //-------------------------------------------------------------------------------------------------------------------
629   // Builder
630   //-------------------------------------------------------------------------------------------------------------------
631
632   /**
633    * Builder class.
634    */
635   public static class Builder {
636      String name, _default;
637      Set<Integer> codes;
638      Set<String> _enum;
639      Boolean allowEmptyValue, exclusiveMaximum, exclusiveMinimum, required, uniqueItems, skipIfEmpty;
640      HttpPartCollectionFormat collectionFormat = HttpPartCollectionFormat.NO_COLLECTION_FORMAT;
641      HttpPartDataType type = HttpPartDataType.NO_TYPE;
642      HttpPartFormat format = HttpPartFormat.NO_FORMAT;
643      Pattern pattern;
644      Number maximum, minimum, multipleOf;
645      Long maxLength, minLength, maxItems, minItems, maxProperties, minProperties;
646      Map<String,Object> properties;
647      Object items, additionalProperties;
648      boolean noValidate;
649      Class<? extends HttpPartParser> parser;
650      Class<? extends HttpPartSerializer> serializer;
651
652      /**
653       * Instantiates a new {@link HttpPartSchema} object based on the configuration of this builder.
654       *
655       * <p>
656       * This method can be called multiple times to produce new schema objects.
657       *
658       * @return
659       *    A new {@link HttpPartSchema} object.
660       *    <br>Never <jk>null</jk>.
661       */
662      public HttpPartSchema build() {
663         return new HttpPartSchema(this);
664      }
665
666      Builder apply(Class<? extends Annotation> c, ParamInfo mpi) {
667         apply(c, mpi.getParameterType().innerType());
668         mpi.forEachDeclaredAnnotation(c, x -> true, x -> apply(x));
669         return this;
670      }
671
672      Builder applyAll(Class<? extends Annotation> c, ParamInfo mpi) {
673         return apply(Schema.class, mpi).apply(c, mpi);
674      }
675
676      Builder apply(Class<? extends Annotation> c, Method m) {
677         apply(c, m.getGenericReturnType());
678         Annotation a = m.getAnnotation(c);
679         if (a != null)
680            return apply(a);
681         return this;
682      }
683
684      Builder applyAll(Class<? extends Annotation> c, Method m) {
685         return apply(Schema.class, m).apply(c, m);
686      }
687
688      Builder apply(Class<? extends Annotation> c, java.lang.reflect.Type t) {
689         if (t instanceof Class<?>) {
690            ClassInfo.of((Class<?>)t).forEachAnnotation(c, x -> true, x -> apply(x));
691         } else if (Value.isType(t)) {
692            apply(c, Value.getParameterType(t));
693         }
694         return this;
695      }
696
697      Builder applyAll(Class<? extends Annotation> c, java.lang.reflect.Type t) {
698         return apply(Schema.class, t).apply(c, t);
699      }
700
701      /**
702       * Apply the specified annotation to this schema.
703       *
704       * @param a The annotation to apply.
705       * @return This object.
706       */
707      public Builder apply(Annotation a) {
708         if (a instanceof Content)
709            apply((Content)a);
710         else if (a instanceof Header)
711            apply((Header)a);
712         else if (a instanceof FormData)
713            apply((FormData)a);
714         else if (a instanceof Query)
715            apply((Query)a);
716         else if (a instanceof Path)
717            apply((Path)a);
718         else if (a instanceof Response)
719            apply((Response)a);
720         else if (a instanceof StatusCode)
721            apply((StatusCode)a);
722         else if (a instanceof HasQuery)
723            apply((HasQuery)a);
724         else if (a instanceof HasFormData)
725            apply((HasFormData)a);
726         else if (a instanceof Schema)
727            apply((Schema)a);
728         else
729            throw new BasicRuntimeException("Builder.apply(@{0}) not defined", className(a));
730         return this;
731      }
732
733      Builder apply(Content a) {
734         if (! SchemaAnnotation.empty(a.schema()))
735            apply(a.schema());
736         return this;
737      }
738
739      Builder apply(Header a) {
740         if (! SchemaAnnotation.empty(a.schema()))
741            apply(a.schema());
742         name(firstNonEmpty(a.name(), a.value()));
743         parser(a.parser());
744         serializer(a.serializer());
745         return this;
746      }
747
748      Builder apply(FormData a) {
749         if (! SchemaAnnotation.empty(a.schema()))
750            apply(a.schema());
751         name(firstNonEmpty(a.name(), a.value()));
752         parser(a.parser());
753         serializer(a.serializer());
754         return this;
755      }
756
757      Builder apply(Query a) {
758         if (! SchemaAnnotation.empty(a.schema()))
759            apply(a.schema());
760         name(firstNonEmpty(a.name(), a.value()));
761         parser(a.parser());
762         serializer(a.serializer());
763         return this;
764      }
765
766      Builder apply(Path a) {
767         if (! SchemaAnnotation.empty(a.schema()))
768            apply(a.schema());
769         name(firstNonEmpty(a.name(), a.value()));
770         parser(a.parser());
771         serializer(a.serializer());
772
773         // Path remainder always allows empty value.
774         if (startsWith(name, '/')) {
775            allowEmptyValue();
776            required(false);
777         } else if (required == null) {
778            required(true);
779         }
780
781         return this;
782      }
783
784      Builder apply(Response a) {
785         allowEmptyValue(true);
786         apply(a.schema());
787         parser(a.parser());
788         required(false);
789         serializer(a.serializer());
790         return this;
791      }
792
793      Builder apply(StatusCode a) {
794         codes(a.value());
795         return this;
796      }
797
798      Builder apply(Items a) {
799         _default(joinnlOrNull(a._default(), a.df()));
800         _enum(toSet(a._enum(), a.e()));
801         collectionFormat(firstNonEmpty(a.collectionFormat(), a.cf()));
802         exclusiveMaximum(a.exclusiveMaximum() || a.emax());
803         exclusiveMinimum(a.exclusiveMinimum() || a.emin());
804         format(firstNonEmpty(a.format(), a.f()));
805         items(a.items());
806         maximum(toNumber(a.maximum(), a.max()));
807         maxItems(firstNmo(a.maxItems(), a.maxi()));
808         maxLength(firstNmo(a.maxLength(), a.maxl()));
809         minimum(toNumber(a.minimum(), a.min()));
810         minItems(firstNmo(a.minItems(), a.mini()));
811         minLength(firstNmo(a.minLength(), a.minl()));
812         multipleOf(toNumber(a.multipleOf(), a.mo()));
813         pattern(firstNonEmpty(a.pattern(), a.p()));
814         type(firstNonEmpty(a.type(), a.t()));
815         uniqueItems(a.uniqueItems() || a.ui());         return this;
816      }
817
818      Builder apply(SubItems a) {
819         _default(joinnlOrNull(a._default(), a.df()));
820         _enum(toSet(a._enum(), a.e()));
821         collectionFormat(firstNonEmpty(a.collectionFormat(), a.cf()));
822         exclusiveMaximum(a.exclusiveMaximum() || a.emax());
823         exclusiveMinimum(a.exclusiveMinimum() || a.emin());
824         format(firstNonEmpty(a.format(), a.f()));
825         items(HttpPartSchema.toJsonMap(a.items()));
826         maximum(toNumber(a.maximum(), a.max()));
827         maxItems(firstNmo(a.maxItems(), a.maxi()));
828         maxLength(firstNmo(a.maxLength(), a.maxl()));
829         minimum(toNumber(a.minimum(), a.min()));
830         minItems(firstNmo(a.minItems(), a.mini()));
831         minLength(firstNmo(a.minLength(), a.minl()));
832         multipleOf(toNumber(a.multipleOf(), a.mo()));
833         pattern(firstNonEmpty(a.pattern(), a.p()));
834         type(firstNonEmpty(a.type(), a.t()));
835         uniqueItems(a.uniqueItems() || a.ui());         return this;
836      }
837
838      Builder apply(Schema a) {
839         _default(joinnlOrNull(a._default(), a.df()));
840         _enum(toSet(a._enum(), a.e()));
841         additionalProperties(HttpPartSchema.toJsonMap(a.additionalProperties()));
842         allowEmptyValue(a.allowEmptyValue() || a.aev());
843         collectionFormat(firstNonEmpty(a.collectionFormat(), a.cf()));
844         exclusiveMaximum(a.exclusiveMaximum() || a.emax());
845         exclusiveMinimum(a.exclusiveMinimum() || a.emin());
846         format(firstNonEmpty(a.format(), a.f()));
847         items(a.items());
848         maximum(toNumber(a.maximum(), a.max()));
849         maxItems(firstNmo(a.maxItems(), a.maxi()));
850         maxLength(firstNmo(a.maxLength(), a.maxl()));
851         maxProperties(firstNmo(a.maxProperties(), a.maxp()));
852         minimum(toNumber(a.minimum(), a.min()));
853         minItems(firstNmo(a.minItems(), a.mini()));
854         minLength(firstNmo(a.minLength(), a.minl()));
855         minProperties(firstNmo(a.minProperties(), a.minp()));
856         multipleOf(toNumber(a.multipleOf(), a.mo()));
857         pattern(firstNonEmpty(a.pattern(), a.p()));
858         properties(HttpPartSchema.toJsonMap(a.properties()));
859         required(a.required() || a.r());
860         skipIfEmpty(a.skipIfEmpty() || a.sie());
861         type(firstNonEmpty(a.type(), a.t()));
862         uniqueItems(a.uniqueItems() || a.ui());
863         return this;
864      }
865
866      Builder apply(HasQuery a) {
867         name(firstNonEmpty(a.name(), a.value()));
868         return this;
869      }
870
871      Builder apply(HasFormData a) {
872         name(firstNonEmpty(a.name(), a.value()));
873         return this;
874      }
875
876      Builder apply(JsonMap m) {
877         if (m != null && ! m.isEmpty()) {
878            _default(m.getString("default"));
879            _enum(HttpPartSchema.toSet(m.getString("enum")));
880            allowEmptyValue(m.getBoolean("allowEmptyValue"));
881            exclusiveMaximum(m.getBoolean("exclusiveMaximum"));
882            exclusiveMinimum(m.getBoolean("exclusiveMinimum"));
883            required(m.getBoolean("required"));
884            uniqueItems(m.getBoolean("uniqueItems"));
885            collectionFormat(m.getString("collectionFormat"));
886            type(m.getString("type"));
887            format(m.getString("format"));
888            pattern(m.getString("pattern"));
889            maximum(m.get("maximum", Number.class));
890            minimum(m.get("minimum", Number.class));
891            multipleOf(m.get("multipleOf", Number.class));
892            maxItems(m.get("maxItems", Long.class));
893            maxLength(m.get("maxLength", Long.class));
894            maxProperties(m.get("maxProperties", Long.class));
895            minItems(m.get("minItems", Long.class));
896            minLength(m.get("minLength", Long.class));
897            minProperties(m.get("minProperties", Long.class));
898
899            items(m.getMap("items"));
900            properties(m.getMap("properties"));
901            additionalProperties(m.getMap("additionalProperties"));
902
903            apply(m.getMap("schema", null));
904         }
905         return this;
906      }
907
908      /**
909       * <mk>name</mk> field.
910       *
911       * <p>
912       * Applicable to the following Swagger schema objects:
913       * <ul>
914       *    <li><a class="doclink" href="https://swagger.io/specification/v2#parameterObject">Parameter</a>
915       *    <li><a class="doclink" href="https://swagger.io/specification/v2#headerObject">Header</a>
916       * </ul>
917       *
918       * @param value
919       *    The new value for this property.
920       * @return This object.
921       */
922      public Builder name(String value) {
923         if (isNotEmpty(value))
924            name = value;
925         return this;
926      }
927
928      /**
929       * Synonym for {@link #name(String)}.
930       *
931       * @param value
932       *    The new value for this property.
933       * @return This object.
934       */
935      public Builder n(String value) {
936         return name(value);
937      }
938
939      /**
940       * <mk>httpStatusCode</mk> key.
941       *
942       * <p>
943       * Applicable to the following Swagger schema objects:
944       * <ul>
945       *    <li><a class="doclink" href="https://swagger.io/specification/v2#responsesObject">Responses</a>
946       * </ul>
947       *
948       * @param value
949       *    The new value for this property.
950       *    <br>Ignored if <jk>null</jk> or an empty array.
951       * @return This object.
952       */
953      public Builder codes(int[] value) {
954         if (value != null && value.length != 0)
955            for (int v : value)
956               code(v);
957         return this;
958      }
959
960      /**
961       * <mk>httpStatusCode</mk> key.
962       *
963       * <p>
964       * Applicable to the following Swagger schema objects:
965       * <ul>
966       *    <li><a class="doclink" href="https://swagger.io/specification/v2#responsesObject">Responses</a>
967       * </ul>
968       *
969       * @param value
970       *    The new value for this property.
971       *    <br>Ignored if value is <c>0</c>.
972       * @return This object.
973       */
974      public Builder code(int value) {
975         if (value != 0) {
976            if (codes == null)
977               codes = new TreeSet<>();
978            codes.add(value);
979         }
980         return this;
981      }
982
983      /**
984       * <mk>required</mk> field.
985       *
986       * <p>
987       * Determines whether the parameter is mandatory.
988       *
989       * <p>
990       * Applicable to the following Swagger schema objects:
991       * <ul>
992       *    <li><a class="doclink" href="https://swagger.io/specification/v2#parameterObject">Parameter</a>
993       *    <li><a class="doclink" href="https://swagger.io/specification/v2#schemaObject">Schema</a>
994       * </ul>
995       *
996       * @param value
997       *    The new value for this property.
998       *    <br>Ignored if value is <jk>null</jk>.
999       * @return This object.
1000       */
1001      public Builder required(Boolean value) {
1002         required = resolve(value, required);
1003         return this;
1004      }
1005
1006      /**
1007       * Synonym for {@link #required(Boolean)}.
1008       *
1009       * @param value
1010       *    The new value for this property.
1011       * @return This object.
1012       */
1013      public Builder r(Boolean value) {
1014         return required(value);
1015      }
1016
1017      /**
1018       * <mk>required</mk> field.
1019       *
1020       * <p>
1021       * Determines whether the parameter is mandatory.
1022       *
1023       * <p>
1024       * Same as {@link #required(Boolean)} but takes in a boolean value as a string.
1025       *
1026       * @param value
1027       *    The new value for this property.
1028       *    <br>Ignored if value is <jk>null</jk> or empty.
1029       * @return This object.
1030       */
1031      public Builder required(String value) {
1032         required = resolve(value, required);
1033         return this;
1034      }
1035
1036      /**
1037       * Synonym for {@link #required(String)}.
1038       *
1039       * @param value
1040       *    The new value for this property.
1041       * @return This object.
1042       */
1043      public Builder r(String value) {
1044         return required(value);
1045      }
1046
1047      /**
1048       * <mk>required</mk> field.
1049       *
1050       * <p>
1051       * Shortcut for calling <code>required(<jk>true</jk>);</code>.
1052       *
1053       * @return This object.
1054       */
1055      public Builder required() {
1056         return required(true);
1057      }
1058
1059      /**
1060       * Synonym for {@link #required()}.
1061       *
1062       * @return This object.
1063       */
1064      public Builder r() {
1065         return required();
1066      }
1067
1068      /**
1069       * <mk>type</mk> field.
1070       *
1071       * <p>
1072       * The type of the parameter.
1073       *
1074       * <p>
1075       * If the type is not specified, it will be auto-detected based on the parameter class type.
1076       *
1077       * <p>
1078       * Applicable to the following Swagger schema objects:
1079       * <ul>
1080       *    <li><a class="doclink" href="https://swagger.io/specification/v2#parameterObject">Parameter</a>
1081       *    <li><a class="doclink" href="https://swagger.io/specification/v2#schemaObject">Schema</a>
1082       *    <li><a class="doclink" href="https://swagger.io/specification/v2#itemsObject">Items</a>
1083       *    <li><a class="doclink" href="https://swagger.io/specification/v2#securitySchemeObject">SecurityScheme</a>
1084       * </ul>
1085       *
1086       * <ul class='values'>
1087       *    <li>
1088       *       <js>"string"</js>
1089       *       <br>Parameter must be a string or a POJO convertible from a string.
1090       *    <li>
1091       *       <js>"number"</js>
1092       *       <br>Parameter must be a number primitive or number object.
1093       *       <br>If parameter is <c>Object</c>, creates either a <c>Float</c> or <c>Double</c> depending on the size of the number.
1094       *    <li>
1095       *       <js>"integer"</js>
1096       *       <br>Parameter must be a integer/long primitive or integer/long object.
1097       *       <br>If parameter is <c>Object</c>, creates either a <c>Short</c>, <c>Integer</c>, or <c>Long</c> depending on the size of the number.
1098       *    <li>
1099       *       <js>"boolean"</js>
1100       *       <br>Parameter must be a boolean primitive or object.
1101       *    <li>
1102       *       <js>"array"</js>
1103       *       <br>Parameter must be an array or collection.
1104       *       <br>Elements must be strings or POJOs convertible from strings.
1105       *       <br>If parameter is <c>Object</c>, creates an {@link JsonList}.
1106       *    <li>
1107       *       <js>"object"</js>
1108       *       <br>Parameter must be a map or bean.
1109       *       <br>If parameter is <c>Object</c>, creates an {@link JsonMap}.
1110       *       <br>Note that this is an extension of the OpenAPI schema as Juneau allows for arbitrarily-complex POJOs to be serialized as HTTP parts.
1111       *    <li>
1112       *       <js>"file"</js>
1113       *       <br>This type is currently not supported.
1114       * </ul>
1115       *
1116       * <h5 class='section'>See Also:</h5><ul>
1117       *    <li class='extlink'><a class="doclink" href="https://swagger.io/specification#dataTypes">Swagger Data Types</a>
1118       * </ul>
1119       *
1120       * @param value
1121       *    The new value for this property.
1122       *    <br>Ignored if value is <jk>null</jk> or empty.
1123       * @return This object.
1124       */
1125      public Builder type(String value) {
1126         try {
1127            if (isNotEmpty(value))
1128               type = HttpPartDataType.fromString(value);
1129         } catch (Exception e) {
1130            throw new ContextRuntimeException("Invalid value ''{0}'' passed in as type value.  Valid values: {1}", value, HttpPartDataType.values());
1131         }
1132         return this;
1133      }
1134
1135      /**
1136       * Synonym for {@link #type(String)}.
1137       *
1138       * @param value
1139       *    The new value for this property.
1140       * @return This object.
1141       */
1142      public Builder t(String value) {
1143         return type(value);
1144      }
1145
1146      /**
1147       * Shortcut for <c>type(HttpPartDataType.STRING)</c>.
1148       *
1149       * @return This object.
1150       */
1151      public Builder tString() {
1152         type = HttpPartDataType.STRING;
1153         return this;
1154      }
1155
1156      /**
1157       * Shortcut for <c>type(HttpPartDataType.NUMBER)</c>.
1158       *
1159       * @return This object.
1160       */
1161      public Builder tNumber() {
1162         type = HttpPartDataType.NUMBER;
1163         return this;
1164      }
1165
1166      /**
1167       * Shortcut for <c>type(HttpPartDataType.INTEGER)</c>.
1168       *
1169       * @return This object.
1170       */
1171      public Builder tInteger() {
1172         type = HttpPartDataType.INTEGER;
1173         return this;
1174      }
1175
1176      /**
1177       * Shortcut for <c>type(HttpPartDataType.BOOLEAN)</c>.
1178       *
1179       * @return This object.
1180       */
1181      public Builder tBoolean() {
1182         type = HttpPartDataType.BOOLEAN;
1183         return this;
1184      }
1185
1186      /**
1187       * Shortcut for <c>type(HttpPartDataType.ARRAY)</c>.
1188       *
1189       * @return This object.
1190       */
1191      public Builder tArray() {
1192         type = HttpPartDataType.ARRAY;
1193         return this;
1194      }
1195
1196      /**
1197       * Shortcut for <c>type(HttpPartDataType.OBJECT)</c>.
1198       *
1199       * @return This object.
1200       */
1201      public Builder tObject() {
1202         type = HttpPartDataType.OBJECT;
1203         return this;
1204      }
1205
1206      /**
1207       * Shortcut for <c>type(HttpPartDataType.FILE)</c>.
1208       *
1209       * @return This object.
1210       */
1211      public Builder tFile() {
1212         type = HttpPartDataType.FILE;
1213         return this;
1214      }
1215
1216      /**
1217       * Shortcut for <c>type(HttpPartDataType.NO_TYPE)</c>.
1218       *
1219       * @return This object.
1220       */
1221      public Builder tNone() {
1222         type = HttpPartDataType.NO_TYPE;
1223         return this;
1224      }
1225
1226      /**
1227       * <mk>type</mk> field.
1228       *
1229       * <p>
1230       * The type of the parameter.
1231       *
1232       * <p>
1233       * If the type is not specified, it will be auto-detected based on the parameter class type.
1234       *
1235       * <p>
1236       * Applicable to the following Swagger schema objects:
1237       * <ul>
1238       *    <li><a class="doclink" href="https://swagger.io/specification/v2#parameterObject">Parameter</a>
1239       *    <li><a class="doclink" href="https://swagger.io/specification/v2#schemaObject">Schema</a>
1240       *    <li><a class="doclink" href="https://swagger.io/specification/v2#itemsObject">Items</a>
1241       *    <li><a class="doclink" href="https://swagger.io/specification/v2#securitySchemeObject">SecurityScheme</a>
1242       * </ul>
1243       *
1244       * <ul class='values javatree'>
1245       *    <li class='jc'>{@link HttpPartDataType}
1246       *    <ul>
1247       *       <li class='jf'>
1248       *          {@link HttpPartDataType#STRING STRING}
1249       *          <br>Parameter must be a string or a POJO convertible from a string.
1250       *          <li>
1251       *          {@link HttpPartDataType#NUMBER NUMBER}
1252       *          <br>Parameter must be a number primitive or number object.
1253       *          <br>If parameter is <c>Object</c>, creates either a <c>Float</c> or <c>Double</c> depending on the size of the number.
1254       *       <li class='jf'>
1255       *          {@link HttpPartDataType#INTEGER INTEGER}
1256       *          <br>Parameter must be a integer/long primitive or integer/long object.
1257       *          <br>If parameter is <c>Object</c>, creates either a <c>Short</c>, <c>Integer</c>, or <c>Long</c> depending on the size of the number.
1258       *       <li class='jf'>
1259       *          {@link HttpPartDataType#BOOLEAN BOOLEAN}
1260       *          <br>Parameter must be a boolean primitive or object.
1261       *       <li class='jf'>
1262       *          {@link HttpPartDataType#ARRAY ARRAY}
1263       *          <br>Parameter must be an array or collection.
1264       *          <br>Elements must be strings or POJOs convertible from strings.
1265       *          <br>If parameter is <c>Object</c>, creates an {@link JsonList}.
1266       *       <li class='jf'>
1267       *          {@link HttpPartDataType#OBJECT OBJECT}
1268       *          <br>Parameter must be a map or bean.
1269       *          <br>If parameter is <c>Object</c>, creates an {@link JsonMap}.
1270       *          <br>Note that this is an extension of the OpenAPI schema as Juneau allows for arbitrarily-complex POJOs to be serialized as HTTP parts.
1271       *       <li class='jf'>
1272       *          {@link HttpPartDataType#FILE FILE}
1273       *          <br>This type is currently not supported.
1274       *    </ul>
1275       * </ul>
1276       *
1277       * <h5 class='section'>See Also:</h5><ul>
1278       *    <li class='extlink'><a class="doclink" href="https://swagger.io/specification#dataTypes">Swagger Data Types</a>
1279       * </ul>
1280       *
1281       * @param value
1282       *    The new value for this property.
1283       * @return This object.
1284       */
1285      public Builder type(HttpPartDataType value) {
1286         this.type = value;
1287         return this;
1288      }
1289
1290      /**
1291       * Synonym for {@link #type(HttpPartDataType)}.
1292       *
1293       * @param value
1294       *    The new value for this property.
1295       * @return This object.
1296       */
1297      public Builder t(HttpPartDataType value) {
1298         return type(value);
1299      }
1300
1301      /**
1302       * <mk>format</mk> field.
1303       *
1304       * <p>
1305       * The extending format for the previously mentioned <a class="doclink" href="https://swagger.io/specification/v2#parameterType">parameter type</a>.
1306       *
1307       * <p>
1308       * Applicable to the following Swagger schema objects:
1309       * <ul>
1310       *    <li><a class="doclink" href="https://swagger.io/specification/v2#parameterObject">Parameter</a>
1311       *    <li><a class="doclink" href="https://swagger.io/specification/v2#schemaObject">Schema</a>
1312       *    <li><a class="doclink" href="https://swagger.io/specification/v2#itemsObject">Items</a>
1313       *    <li><a class="doclink" href="https://swagger.io/specification/v2#headerObject">Header</a>
1314       * </ul>
1315       *
1316       * <ul class='values'>
1317       *    <li>
1318       *       <js>"int32"</js> - Signed 32 bits.
1319       *       <br>Only valid with type <js>"integer"</js>.
1320       *    <li>
1321       *       <js>"int64"</js> - Signed 64 bits.
1322       *       <br>Only valid with type <js>"integer"</js>.
1323       *    <li>
1324       *       <js>"float"</js> - 32-bit floating point number.
1325       *       <br>Only valid with type <js>"number"</js>.
1326       *    <li>
1327       *       <js>"double"</js> - 64-bit floating point number.
1328       *       <br>Only valid with type <js>"number"</js>.
1329       *    <li>
1330       *       <js>"byte"</js> - BASE-64 encoded characters.
1331       *       <br>Only valid with type <js>"string"</js>.
1332       *       <br>Parameters of type POJO convertible from string are converted after the string has been decoded.
1333       *    <li>
1334       *       <js>"binary"</js> - Hexadecimal encoded octets (e.g. <js>"00FF"</js>).
1335       *       <br>Only valid with type <js>"string"</js>.
1336       *       <br>Parameters of type POJO convertible from string are converted after the string has been decoded.
1337       *    <li>
1338       *       <js>"binary-spaced"</js> - Hexadecimal encoded octets, spaced (e.g. <js>"00 FF"</js>).
1339       *       <br>Only valid with type <js>"string"</js>.
1340       *       <br>Parameters of type POJO convertible from string are converted after the string has been decoded.
1341       *    <li>
1342       *       <js>"date"</js> - An <a href='http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14'>RFC3339 full-date</a>.
1343       *       <br>Only valid with type <js>"string"</js>.
1344       *    <li>
1345       *       <js>"date-time"</js> - An <a href='http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14'>RFC3339 date-time</a>.
1346       *       <br>Only valid with type <js>"string"</js>.
1347       *    <li>
1348       *       <js>"password"</js> - Used to hint UIs the input needs to be obscured.
1349       *       <br>This format does not affect the serialization or parsing of the parameter.
1350       *    <li>
1351       *       <js>"uon"</js> - UON notation (e.g. <js>"(foo=bar,baz=@(qux,123))"</js>).
1352       *       <br>Only valid with type <js>"object"</js>.
1353       *       <br>If not specified, then the input is interpreted as plain-text and is converted to a POJO directly.
1354       * </ul>
1355       *
1356       * <h5 class='section'>See Also:</h5><ul>
1357       *    <li class='extlink'><a class="doclink" href="https://swagger.io/specification/v2#schemaObject">Swagger Schema Object</a>
1358       * </ul>
1359       *
1360       * @param value
1361       *    The new value for this property.
1362       *    <br>Ignored if value is <jk>null</jk> or an empty string.
1363       * @return This object.
1364       */
1365      public Builder format(String value) {
1366         try {
1367            if (isNotEmpty(value))
1368               format = HttpPartFormat.fromString(value);
1369         } catch (Exception e) {
1370            throw new ContextRuntimeException("Invalid value ''{0}'' passed in as format value.  Valid values: {1}", value, HttpPartFormat.values());
1371         }
1372         return this;
1373      }
1374
1375      /**
1376       * Synonym for {@link #format(String)}.
1377       *
1378       * @param value
1379       *    The new value for this property.
1380       * @return This object.
1381       */
1382      public Builder f(String value) {
1383         return format(value);
1384      }
1385
1386      /**
1387       * <mk>format</mk> field.
1388       *
1389       * <p>
1390       * The extending format for the previously mentioned <a class="doclink" href="https://swagger.io/specification/v2#parameterType">parameter type</a>.
1391       *
1392       * <p>
1393       * Applicable to the following Swagger schema objects:
1394       * <ul>
1395       *    <li><a class="doclink" href="https://swagger.io/specification/v2#parameterObject">Parameter</a>
1396       *    <li><a class="doclink" href="https://swagger.io/specification/v2#schemaObject">Schema</a>
1397       *    <li><a class="doclink" href="https://swagger.io/specification/v2#itemsObject">Items</a>
1398       *    <li><a class="doclink" href="https://swagger.io/specification/v2#headerObject">Header</a>
1399       * </ul>
1400       *
1401       * <ul class='values javatree'>
1402       *    <ul class='jc'>{@link HttpPartFormat}
1403       *    <ul>
1404       *       <li class='jf'>
1405       *          {@link HttpPartFormat#INT32 INT32} - Signed 32 bits.
1406       *          <br>Only valid with type <js>"integer"</js>.
1407       *       <li class='jf'>
1408       *          {@link HttpPartFormat#INT64 INT64} - Signed 64 bits.
1409       *          <br>Only valid with type <js>"integer"</js>.
1410       *       <li class='jf'>
1411       *          {@link HttpPartFormat#FLOAT FLOAT} - 32-bit floating point number.
1412       *          <br>Only valid with type <js>"number"</js>.
1413       *       <li class='jf'>
1414       *          {@link HttpPartFormat#DOUBLE DOUBLE} - 64-bit floating point number.
1415       *          <br>Only valid with type <js>"number"</js>.
1416       *       <li class='jf'>
1417       *          {@link HttpPartFormat#BYTE BYTE} - BASE-64 encoded characters.
1418       *          <br>Only valid with type <js>"string"</js>.
1419       *          <br>Parameters of type POJO convertible from string are converted after the string has been decoded.
1420       *       <li class='jf'>
1421       *          {@link HttpPartFormat#BINARY BINARY} - Hexadecimal encoded octets (e.g. <js>"00FF"</js>).
1422       *          <br>Only valid with type <js>"string"</js>.
1423       *          <br>Parameters of type POJO convertible from string are converted after the string has been decoded.
1424       *       <li class='jf'>
1425       *          {@link HttpPartFormat#BINARY_SPACED BINARY_SPACED} - Hexadecimal encoded octets, spaced (e.g. <js>"00 FF"</js>).
1426       *          <br>Only valid with type <js>"string"</js>.
1427       *          <br>Parameters of type POJO convertible from string are converted after the string has been decoded.
1428       *       <li class='jf'>
1429       *          {@link HttpPartFormat#DATE DATE} - An <a href='http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14'>RFC3339 full-date</a>.
1430       *          <br>Only valid with type <js>"string"</js>.
1431       *       <li class='jf'>
1432       *          {@link HttpPartFormat#DATE_TIME DATE_TIME} - An <a href='http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14'>RFC3339 date-time</a>.
1433       *          <br>Only valid with type <js>"string"</js>.
1434       *       <li class='jf'>
1435       *          {@link HttpPartFormat#PASSWORD PASSWORD} - Used to hint UIs the input needs to be obscured.
1436       *          <br>This format does not affect the serialization or parsing of the parameter.
1437       *       <li class='jf'>
1438       *          {@link HttpPartFormat#UON UON} - UON notation (e.g. <js>"(foo=bar,baz=@(qux,123))"</js>).
1439       *          <br>Only valid with type <js>"object"</js>.
1440       *          <br>If not specified, then the input is interpreted as plain-text and is converted to a POJO directly.
1441       *    </ul>
1442       * </ul>
1443       *
1444       * <h5 class='section'>See Also:</h5><ul>
1445       *    <li class='extlink'><a class="doclink" href="https://swagger.io/specification/v2#schemaObject">Swagger Schema Object</a>
1446       * </ul>
1447       *
1448       * @param value
1449       *    The new value for this property.
1450       * @return This object.
1451       */
1452      public Builder format(HttpPartFormat value) {
1453         format = value;
1454         return this;
1455      }
1456
1457      /**
1458       * Synonym for {@link #format(HttpPartFormat)}.
1459       *
1460       * @param value
1461       *    The new value for this property.
1462       * @return This object.
1463       */
1464      public Builder f(HttpPartFormat value) {
1465         return format(value);
1466      }
1467
1468      /**
1469       * Shortcut for <c>format(HttpPartFormat.INT32)</c>.
1470       *
1471       * @return This object.
1472       */
1473      public Builder fInt32() {
1474         format = HttpPartFormat.INT32;
1475         return this;
1476      }
1477
1478      /**
1479       * Shortcut for <c>format(HttpPartFormat.INT64)</c>.
1480       *
1481       * @return This object.
1482       */
1483      public Builder fInt64() {
1484         format = HttpPartFormat.INT64;
1485         return this;
1486      }
1487
1488      /**
1489       * Shortcut for <c>format(HttpPartFormat.FLOAT)</c>.
1490       *
1491       * @return This object.
1492       */
1493      public Builder fFloat() {
1494         format = HttpPartFormat.FLOAT;
1495         return this;
1496      }
1497
1498      /**
1499       * Shortcut for <c>format(HttpPartFormat.DOUBLE)</c>.
1500       *
1501       * @return This object.
1502       */
1503      public Builder fDouble() {
1504         format = HttpPartFormat.DOUBLE;
1505         return this;
1506      }
1507
1508      /**
1509       * Shortcut for <c>format(HttpPartFormat.BYTE)</c>.
1510       *
1511       * @return This object.
1512       */
1513      public Builder fByte() {
1514         format = HttpPartFormat.BYTE;
1515         return this;
1516      }
1517
1518      /**
1519       * Shortcut for <c>format(HttpPartFormat.BINARY)</c>.
1520       *
1521       * @return This object.
1522       */
1523      public Builder fBinary() {
1524         format = HttpPartFormat.BINARY;
1525         return this;
1526      }
1527
1528      /**
1529       * Shortcut for <c>format(HttpPartFormat.BINARY_SPACED)</c>.
1530       *
1531       * @return This object.
1532       */
1533      public Builder fBinarySpaced() {
1534         format = HttpPartFormat.BINARY_SPACED;
1535         return this;
1536      }
1537
1538      /**
1539       * Shortcut for <c>format(HttpPartFormat.DATE)</c>.
1540       *
1541       * @return This object.
1542       */
1543      public Builder fDate() {
1544         format = HttpPartFormat.DATE;
1545         return this;
1546      }
1547
1548      /**
1549       * Shortcut for <c>format(HttpPartFormat.DATE_TIME)</c>.
1550       *
1551       * @return This object.
1552       */
1553      public Builder fDateTime() {
1554         format = HttpPartFormat.DATE_TIME;
1555         return this;
1556      }
1557
1558      /**
1559       * Shortcut for <c>format(HttpPartFormat.PASSWORD)</c>.
1560       *
1561       * @return This object.
1562       */
1563      public Builder fPassword() {
1564         format = HttpPartFormat.PASSWORD;
1565         return this;
1566      }
1567
1568      /**
1569       * Shortcut for <c>format(HttpPartFormat.UON)</c>.
1570       *
1571       * @return This object.
1572       */
1573      public Builder fUon() {
1574         format = HttpPartFormat.UON;
1575         return this;
1576      }
1577
1578      /**
1579       * Shortcut for <c>format(HttpPartFormat.NO_FORMAT)</c>.
1580       *
1581       * @return This object.
1582       */
1583      public Builder fNone() {
1584         format = HttpPartFormat.NO_FORMAT;
1585         return this;
1586      }
1587
1588      /**
1589       * <mk>allowEmptyValue</mk> field.
1590       *
1591       * <p>
1592       * Sets the ability to pass empty-valued parameters.
1593       * <br>This is valid only for either query or formData parameters and allows you to send a parameter with a name only or an empty value.
1594       * <br>The default value is <jk>false</jk>.
1595       *
1596       * <p>
1597       * Applicable to the following Swagger schema objects:
1598       * <ul>
1599       *    <li><a class="doclink" href="https://swagger.io/specification/v2#parameterObject">Parameter</a>
1600       * </ul>
1601       *
1602       * @param value
1603       *    The new value for this property.
1604       *    <br>Ignored if value is <jk>null</jk>.
1605       * @return This object.
1606       */
1607      public Builder allowEmptyValue(Boolean value) {
1608         allowEmptyValue = resolve(value, allowEmptyValue);
1609         return this;
1610      }
1611
1612      /**
1613       * Synonym for {@link #allowEmptyValue(Boolean)}.
1614       *
1615       * @param value
1616       *    The new value for this property.
1617       * @return This object.
1618       */
1619      public Builder aev(Boolean value) {
1620         return allowEmptyValue(value);
1621      }
1622
1623      /**
1624       * <mk>allowEmptyValue</mk> field.
1625       *
1626       * <p>
1627       * Same as {@link #allowEmptyValue(Boolean)} but takes in a string boolean value.
1628       *
1629       * @param value
1630       *    The new value for this property.
1631       *    <br>Ignored if value is <jk>null</jk> or empty.
1632       * @return This object.
1633       */
1634      public Builder allowEmptyValue(String value) {
1635         allowEmptyValue = resolve(value, allowEmptyValue);
1636         return this;
1637      }
1638
1639      /**
1640       * Synonym for {@link #allowEmptyValue(String)}.
1641       *
1642       * @param value
1643       *    The new value for this property.
1644       * @return This object.
1645       */
1646      public Builder aev(String value) {
1647         return allowEmptyValue(value);
1648      }
1649
1650      /**
1651       * <mk>allowEmptyValue</mk> field.
1652       *
1653       * <p>
1654       * Shortcut for calling <code>allowEmptyValue(<jk>true</jk>);</code>.
1655       *
1656       * @return This object.
1657       */
1658      public Builder allowEmptyValue() {
1659         return allowEmptyValue(true);
1660      }
1661
1662      /**
1663       * Synonym for {@link #allowEmptyValue()}.
1664       *
1665       * @return This object.
1666       */
1667      public Builder aev() {
1668         return allowEmptyValue(true);
1669      }
1670
1671      /**
1672       * <mk>items</mk> field.
1673       *
1674       * <p>
1675       * Describes the type of items in the array.
1676       * <p>
1677       * Required if <c>type</c> is <js>"array"</js>.
1678       * <br>Can only be used if <c>type</c> is <js>"array"</js>.
1679       *
1680       * <p>
1681       * Applicable to the following Swagger schema objects:
1682       * <ul>
1683       *    <li><a class="doclink" href="https://swagger.io/specification/v2#parameterObject">Parameter</a>
1684       *    <li><a class="doclink" href="https://swagger.io/specification/v2#schemaObject">Schema</a>
1685       *    <li><a class="doclink" href="https://swagger.io/specification/v2#itemsObject">Items</a>
1686       *    <li><a class="doclink" href="https://swagger.io/specification/v2#headerObject">Header</a>
1687       * </ul>
1688       *
1689       * @param value
1690       *    The new value for this property.
1691       *    <br>Ignored if value is <jk>null</jk> or empty.
1692       * @return This object.
1693       */
1694      public Builder items(Builder value) {
1695         if (value != null)
1696            this.items = value;
1697         return this;
1698      }
1699
1700      /**
1701       * Synonym for {@link #items(HttpPartSchema.Builder)}.
1702       *
1703       * @param value
1704       *    The new value for this property.
1705       * @return This object.
1706       */
1707      public Builder i(Builder value) {
1708         return items(value);
1709      }
1710
1711      /**
1712       * <mk>items</mk> field.
1713       *
1714       * <p>
1715       * Describes the type of items in the array.
1716       * <p>
1717       * Required if <c>type</c> is <js>"array"</js>.
1718       * <br>Can only be used if <c>type</c> is <js>"array"</js>.
1719       *
1720       * <p>
1721       * Applicable to the following Swagger schema objects:
1722       * <ul>
1723       *    <li><a class="doclink" href="https://swagger.io/specification/v2#parameterObject">Parameter</a>
1724       *    <li><a class="doclink" href="https://swagger.io/specification/v2#schemaObject">Schema</a>
1725       *    <li><a class="doclink" href="https://swagger.io/specification/v2#itemsObject">Items</a>
1726       *    <li><a class="doclink" href="https://swagger.io/specification/v2#headerObject">Header</a>
1727       * </ul>
1728       *
1729       * @param value
1730       *    The new value for this property.
1731       *    <br>Ignored if value is <jk>null</jk> or empty.
1732       * @return This object.
1733       */
1734      public Builder items(HttpPartSchema value) {
1735         if (value != null)
1736            this.items = value;
1737         return this;
1738      }
1739
1740      /**
1741       * Synonym for {@link #items(HttpPartSchema)}.
1742       *
1743       * @param value
1744       *    The new value for this property.
1745       * @return This object.
1746       */
1747      public Builder i(HttpPartSchema value) {
1748         return items(value);
1749      }
1750
1751      Builder items(JsonMap value) {
1752         if (value != null && ! value.isEmpty())
1753            items = HttpPartSchema.create().apply(value);
1754         return this;
1755      }
1756
1757      Builder items(Items value) {
1758         if (! ItemsAnnotation.empty(value))
1759            items = HttpPartSchema.create().apply(value);
1760         return this;
1761      }
1762
1763      Builder items(SubItems value) {
1764         if (! SubItemsAnnotation.empty(value))
1765            items = HttpPartSchema.create().apply(value);
1766         return this;
1767      }
1768
1769
1770      /**
1771       * <mk>collectionFormat</mk> field.
1772       *
1773       * <p>
1774       * Determines the format of the array if <c>type</c> <js>"array"</js> is used.
1775       * <br>Can only be used if <c>type</c> is <js>"array"</js>.
1776       *
1777       * <p>
1778       * Applicable to the following Swagger schema objects:
1779       * <ul>
1780       *    <li><a class="doclink" href="https://swagger.io/specification/v2#parameterObject">Parameter</a>
1781       *    <li><a class="doclink" href="https://swagger.io/specification/v2#itemsObject">Items</a>
1782       *    <li><a class="doclink" href="https://swagger.io/specification/v2#headerObject">Header</a>
1783       * </ul>
1784       *
1785       * <p>
1786       * Note that for collections/arrays parameters with POJO element types, the input is broken into a string array before being converted into POJO elements.
1787       *
1788       * <ul class='values'>
1789       *    <li>
1790       *       <js>"csv"</js> (default) - Comma-separated values (e.g. <js>"foo,bar"</js>).
1791       *    <li>
1792       *       <js>"ssv"</js> - Space-separated values (e.g. <js>"foo bar"</js>).
1793       *    <li>
1794       *       <js>"tsv"</js> - Tab-separated values (e.g. <js>"foo\tbar"</js>).
1795       *    <li>
1796       *       <js>"pipes</js> - Pipe-separated values (e.g. <js>"foo|bar"</js>).
1797       *    <li>
1798       *       <js>"multi"</js> - Corresponds to multiple parameter instances instead of multiple values for a single instance (e.g. <js>"foo=bar&amp;foo=baz"</js>).
1799       *    <li>
1800       *       <js>"uon"</js> - UON notation (e.g. <js>"@(foo,bar)"</js>).
1801       *    <li>
1802       * </ul>
1803       *
1804       * @param value
1805       *    The new value for this property.
1806       *    <br>Ignored if value is <jk>null</jk> or empty.
1807       * @return This object.
1808       */
1809      public Builder collectionFormat(String value) {
1810         try {
1811            if (isNotEmpty(value))
1812               this.collectionFormat = HttpPartCollectionFormat.fromString(value);
1813         } catch (Exception e) {
1814            throw new ContextRuntimeException("Invalid value ''{0}'' passed in as collectionFormat value.  Valid values: {1}", value, HttpPartCollectionFormat.values());
1815         }
1816         return this;
1817      }
1818
1819      /**
1820       * Synonym for {@link #collectionFormat(String)}.
1821       *
1822       * @param value
1823       *    The new value for this property.
1824       * @return This object.
1825       */
1826      public Builder cf(String value) {
1827         return collectionFormat(value);
1828      }
1829
1830      /**
1831       * <mk>collectionFormat</mk> field.
1832       *
1833       * <p>
1834       * Determines the format of the array if <c>type</c> <js>"array"</js> is used.
1835       * <br>Can only be used if <c>type</c> is <js>"array"</js>.
1836       *
1837       * <p>
1838       * Applicable to the following Swagger schema objects:
1839       * <ul>
1840       *    <li><a class="doclink" href="https://swagger.io/specification/v2#parameterObject">Parameter</a>
1841       *    <li><a class="doclink" href="https://swagger.io/specification/v2#itemsObject">Items</a>
1842       *    <li><a class="doclink" href="https://swagger.io/specification/v2#headerObject">Header</a>
1843       * </ul>
1844       *
1845       * <p>
1846       * Note that for collections/arrays parameters with POJO element types, the input is broken into a string array before being converted into POJO elements.
1847       *
1848       * <ul class='values javatree'>
1849       *    <ul class='jc'>{@link HttpPartCollectionFormat}
1850       *    <ul>
1851       *       <li>
1852       *          {@link HttpPartCollectionFormat#CSV CSV} (default) - Comma-separated values (e.g. <js>"foo,bar"</js>).
1853       *       <li>
1854       *          {@link HttpPartCollectionFormat#SSV SSV} - Space-separated values (e.g. <js>"foo bar"</js>).
1855       *       <li>
1856       *          {@link HttpPartCollectionFormat#TSV TSV} - Tab-separated values (e.g. <js>"foo\tbar"</js>).
1857       *       <li>
1858       *          {@link HttpPartCollectionFormat#PIPES PIPES} - Pipe-separated values (e.g. <js>"foo|bar"</js>).
1859       *       <li>
1860       *          {@link HttpPartCollectionFormat#MULTI MULTI} - Corresponds to multiple parameter instances instead of multiple values for a single instance (e.g. <js>"foo=bar&amp;foo=baz"</js>).
1861       *       <li>
1862       *          {@link HttpPartCollectionFormat#UONC UONC} - UON collection notation (e.g. <js>"@(foo,bar)"</js>).
1863       *    </ul>
1864       * </ul>
1865       *
1866       * @param value
1867       *    The new value for this property.
1868       * @return This object.
1869       */
1870      public Builder collectionFormat(HttpPartCollectionFormat value) {
1871         collectionFormat = value;
1872         return this;
1873      }
1874
1875      /**
1876       * Synonym for {@link #collectionFormat(HttpPartCollectionFormat)}.
1877       *
1878       * @param value
1879       *    The new value for this property.
1880       * @return This object.
1881       */
1882      public Builder cf(HttpPartCollectionFormat value) {
1883         return collectionFormat(value);
1884      }
1885
1886      /**
1887       * Shortcut for <c>collectionFormat(HttpPartCollectionFormat.CSV)</c>.
1888       *
1889       * @return This object.
1890       */
1891      public Builder cfCsv() {
1892         return collectionFormat(HttpPartCollectionFormat.CSV);
1893      }
1894
1895      /**
1896       * Shortcut for <c>collectionFormat(HttpPartCollectionFormat.SSV)</c>.
1897       *
1898       * @return This object.
1899       */
1900      public Builder cfSsv() {
1901         return collectionFormat(HttpPartCollectionFormat.SSV);
1902      }
1903
1904      /**
1905       * Shortcut for <c>collectionFormat(HttpPartCollectionFormat.TSV)</c>.
1906       *
1907       * @return This object.
1908       */
1909      public Builder cfTsv() {
1910         return collectionFormat(HttpPartCollectionFormat.TSV);
1911      }
1912
1913      /**
1914       * Shortcut for <c>collectionFormat(HttpPartCollectionFormat.PIPES)</c>.
1915       *
1916       * @return This object.
1917       */
1918      public Builder cfPipes() {
1919         return collectionFormat(HttpPartCollectionFormat.PIPES);
1920      }
1921
1922      /**
1923       * Shortcut for <c>collectionFormat(HttpPartCollectionFormat.MULTI)</c>.
1924       *
1925       * @return This object.
1926       */
1927      public Builder cfMulti() {
1928         return collectionFormat(HttpPartCollectionFormat.MULTI);
1929      }
1930
1931      /**
1932       * Shortcut for <c>collectionFormat(HttpPartCollectionFormat.UONC)</c>.
1933       *
1934       * @return This object.
1935       */
1936      public Builder cfUon() {
1937         return collectionFormat(HttpPartCollectionFormat.UONC);
1938      }
1939
1940      /**
1941       * Shortcut for <c>collectionFormat(HttpPartCollectionFormat.NO_COLLECTION_FORMAT)</c>.
1942       *
1943       * @return This object.
1944       */
1945      public Builder cfNone() {
1946         return collectionFormat(HttpPartCollectionFormat.NO_COLLECTION_FORMAT);
1947      }
1948
1949      /**
1950       * <mk>default</mk> field.
1951       *
1952       * <p>
1953       * Declares the value of the parameter that the server will use if none is provided, for example a "count" to control the number of results per page might default to 100 if not supplied by the client in the request.
1954       * <br>(Note: "default" has no meaning for required parameters.)
1955       *
1956       * <p>
1957       * Applicable to the following Swagger schema objects:
1958       * <ul>
1959       *    <li><a class="doclink" href="https://swagger.io/specification/v2#parameterObject">Parameter</a>
1960       *    <li><a class="doclink" href="https://swagger.io/specification/v2#schemaObject">Schema</a>
1961       *    <li><a class="doclink" href="https://swagger.io/specification/v2#itemsObject">Items</a>
1962       *    <li><a class="doclink" href="https://swagger.io/specification/v2#headerObject">Header</a>
1963       * </ul>
1964       *
1965       * @param value
1966       *    The new value for this property.
1967       *    <br>Ignored if value is <jk>null</jk>.
1968       * @return This object.
1969       */
1970      public Builder _default(String value) {
1971         if (value != null)
1972            this._default = value;
1973         return this;
1974      }
1975
1976      /**
1977       * Synonym for {@link #_default(String)}.
1978       *
1979       * @param value
1980       *    The new value for this property.
1981       * @return This object.
1982       */
1983      public Builder df(String value) {
1984         return _default(value);
1985      }
1986
1987      /**
1988       * <mk>maximum</mk> field.
1989       *
1990       * <p>
1991       * Defines the maximum value for a parameter of numeric types.
1992       *
1993       * <p>
1994       * Only allowed for the following types: <js>"integer"</js>, <js>"number"</js>.
1995       *
1996       * <p>
1997       * Applicable to the following Swagger schema objects:
1998       * <ul>
1999       *    <li><a class="doclink" href="https://swagger.io/specification/v2#parameterObject">Parameter</a>
2000       *    <li><a class="doclink" href="https://swagger.io/specification/v2#schemaObject">Schema</a>
2001       *    <li><a class="doclink" href="https://swagger.io/specification/v2#itemsObject">Items</a>
2002       *    <li><a class="doclink" href="https://swagger.io/specification/v2#headerObject">Header</a>
2003       * </ul>
2004       *
2005       * @param value
2006       *    The new value for this property.
2007       *    <br>Ignored if value is <jk>null</jk>.
2008       * @return This object.
2009       */
2010      public Builder maximum(Number value) {
2011         if (value != null)
2012            this.maximum = value;
2013         return this;
2014      }
2015
2016      /**
2017       * Synonym for {@link #maximum(Number)}.
2018       *
2019       * @param value
2020       *    The new value for this property.
2021       * @return This object.
2022       */
2023      public Builder max(Number value) {
2024         return maximum(value);
2025      }
2026
2027      /**
2028       * <mk>exclusiveMaximum</mk> field.
2029       *
2030       * <p>
2031       * Defines whether the maximum is matched exclusively.
2032       *
2033       * <p>
2034       * Only allowed for the following types: <js>"integer"</js>, <js>"number"</js>.
2035       * <br>If <jk>true</jk>, must be accompanied with <c>maximum</c>.
2036       *
2037       * <p>
2038       * Applicable to the following Swagger schema objects:
2039       * <ul>
2040       *    <li><a class="doclink" href="https://swagger.io/specification/v2#parameterObject">Parameter</a>
2041       *    <li><a class="doclink" href="https://swagger.io/specification/v2#schemaObject">Schema</a>
2042       *    <li><a class="doclink" href="https://swagger.io/specification/v2#itemsObject">Items</a>
2043       *    <li><a class="doclink" href="https://swagger.io/specification/v2#headerObject">Header</a>
2044       * </ul>
2045       *
2046       * @param value
2047       *    The new value for this property.
2048       *    <br>Ignored if value is <jk>null</jk>.
2049       * @return This object.
2050       */
2051      public Builder exclusiveMaximum(Boolean value) {
2052         exclusiveMaximum = resolve(value, exclusiveMaximum);
2053         return this;
2054      }
2055
2056      /**
2057       * Synonym for {@link #exclusiveMaximum(Boolean)}.
2058       *
2059       * @param value
2060       *    The new value for this property.
2061       * @return This object.
2062       */
2063      public Builder emax(Boolean value) {
2064         return exclusiveMaximum(value);
2065      }
2066
2067      /**
2068       * <mk>exclusiveMaximum</mk> field.
2069       *
2070       * <p>
2071       * Same as {@link #exclusiveMaximum(Boolean)} but takes in a string boolean value.
2072       *
2073       * @param value
2074       *    The new value for this property.
2075       *    <br>Ignored if value is <jk>null</jk> or empty.
2076       * @return This object.
2077       */
2078      public Builder exclusiveMaximum(String value) {
2079         exclusiveMaximum = resolve(value, exclusiveMaximum);
2080         return this;
2081      }
2082
2083      /**
2084       * Synonym for {@link #exclusiveMaximum(String)}.
2085       *
2086       * @param value
2087       *    The new value for this property.
2088       * @return This object.
2089       */
2090      public Builder emax(String value) {
2091         return exclusiveMaximum(value);
2092      }
2093
2094      /**
2095       * <mk>exclusiveMaximum</mk> field.
2096       *
2097       * <p>
2098       * Shortcut for calling <code>exclusiveMaximum(<jk>true</jk>);</code>.
2099       *
2100       * @return This object.
2101       */
2102      public Builder exclusiveMaximum() {
2103         return exclusiveMaximum(true);
2104      }
2105
2106      /**
2107       * Synonym for {@link #exclusiveMaximum()}.
2108       *
2109       * @return This object.
2110       */
2111      public Builder emax() {
2112         return exclusiveMaximum();
2113      }
2114
2115      /**
2116       * <mk>minimum</mk> field.
2117       *
2118       * <p>
2119       * Defines the minimum value for a parameter of numeric types.
2120       *
2121       * <p>
2122       * Only allowed for the following types: <js>"integer"</js>, <js>"number"</js>.
2123       *
2124       * <p>
2125       * Applicable to the following Swagger schema objects:
2126       * <ul>
2127       *    <li><a class="doclink" href="https://swagger.io/specification/v2#parameterObject">Parameter</a>
2128       *    <li><a class="doclink" href="https://swagger.io/specification/v2#schemaObject">Schema</a>
2129       *    <li><a class="doclink" href="https://swagger.io/specification/v2#itemsObject">Items</a>
2130       *    <li><a class="doclink" href="https://swagger.io/specification/v2#headerObject">Header</a>
2131       * </ul>
2132       *
2133       * @param value
2134       *    The new value for this property.
2135       *    <br>Ignored if value is <jk>null</jk>.
2136       * @return This object.
2137       */
2138      public Builder minimum(Number value) {
2139         if (value != null)
2140            this.minimum = value;
2141         return this;
2142      }
2143
2144      /**
2145       * Synonym for {@link #minimum(Number)}.
2146       *
2147       * @param value
2148       *    The new value for this property.
2149       * @return This object.
2150       */
2151      public Builder min(Number value) {
2152         return minimum(value);
2153      }
2154
2155      /**
2156       * <mk>exclusiveMinimum</mk> field.
2157       *
2158       * <p>
2159       * Defines whether the minimum is matched exclusively.
2160       *
2161       * <p>
2162       * Only allowed for the following types: <js>"integer"</js>, <js>"number"</js>.
2163       * <br>If <jk>true</jk>, must be accompanied with <c>minimum</c>.
2164       *
2165       * <p>
2166       * Applicable to the following Swagger schema objects:
2167       * <ul>
2168       *    <li><a class="doclink" href="https://swagger.io/specification/v2#parameterObject">Parameter</a>
2169       *    <li><a class="doclink" href="https://swagger.io/specification/v2#schemaObject">Schema</a>
2170       *    <li><a class="doclink" href="https://swagger.io/specification/v2#itemsObject">Items</a>
2171       *    <li><a class="doclink" href="https://swagger.io/specification/v2#headerObject">Header</a>
2172       * </ul>
2173       *
2174       * @param value
2175       *    The new value for this property.
2176       *    <br>Ignored if value is <jk>null</jk>.
2177       * @return This object.
2178       */
2179      public Builder exclusiveMinimum(Boolean value) {
2180         exclusiveMinimum = resolve(value, exclusiveMinimum);
2181         return this;
2182      }
2183
2184      /**
2185       * Synonym for {@link #exclusiveMinimum(Boolean)}.
2186       *
2187       * @param value
2188       *    The new value for this property.
2189       * @return This object.
2190       */
2191      public Builder emin(Boolean value) {
2192         return exclusiveMinimum(value);
2193      }
2194
2195      /**
2196       * <mk>exclusiveMinimum</mk> field.
2197       *
2198       * <p>
2199       * Same as {@link #exclusiveMinimum(Boolean)} but takes in a string boolean value.
2200       *
2201       * @param value
2202       *    The new value for this property.
2203       *    <br>Ignored if value is <jk>null</jk> or empty.
2204       * @return This object.
2205       */
2206      public Builder exclusiveMinimum(String value) {
2207         exclusiveMinimum = resolve(value, exclusiveMinimum);
2208         return this;
2209      }
2210
2211      /**
2212       * Synonym for {@link #exclusiveMinimum(String)}.
2213       *
2214       * @param value
2215       *    The new value for this property.
2216       * @return This object.
2217       */
2218      public Builder emin(String value) {
2219         return exclusiveMinimum(value);
2220      }
2221
2222      /**
2223       * <mk>exclusiveMinimum</mk> field.
2224       *
2225       * <p>
2226       * Shortcut for calling <code>exclusiveMinimum(<jk>true</jk>);</code>.
2227       *
2228       * @return This object.
2229       */
2230      public Builder exclusiveMinimum() {
2231         return exclusiveMinimum(true);
2232      }
2233
2234      /**
2235       * Synonym for {@link #exclusiveMinimum()}.
2236       *
2237       * @return This object.
2238       */
2239      public Builder emin() {
2240         return exclusiveMinimum();
2241      }
2242
2243      /**
2244       * <mk>maxLength</mk> field.
2245       *
2246       * <p>
2247       * A string instance is valid against this keyword if its length is less than, or equal to, the value of this keyword.
2248       * <br>The length of a string instance is defined as the number of its characters as defined by <a href='https://tools.ietf.org/html/rfc4627'>RFC 4627</a>.
2249       *
2250       * <p>
2251       * Only allowed for the following types: <js>"string"</js>.
2252       *
2253       * <p>
2254       * Applicable to the following Swagger schema objects:
2255       * <ul>
2256       *    <li><a class="doclink" href="https://swagger.io/specification/v2#parameterObject">Parameter</a>
2257       *    <li><a class="doclink" href="https://swagger.io/specification/v2#schemaObject">Schema</a>
2258       *    <li><a class="doclink" href="https://swagger.io/specification/v2#itemsObject">Items</a>
2259       *    <li><a class="doclink" href="https://swagger.io/specification/v2#headerObject">Header</a>
2260       * </ul>
2261       *
2262       * @param value
2263       *    The new value for this property.
2264       *    <br>Ignored if value is <jk>null</jk> or <c>-1</c>.
2265       * @return This object.
2266       */
2267      public Builder maxLength(Long value) {
2268         maxLength = resolve(value, maxLength);
2269         return this;
2270      }
2271
2272      /**
2273       * Synonym for {@link #maxLength(Long)}.
2274       *
2275       * @param value
2276       *    The new value for this property.
2277       * @return This object.
2278       */
2279      public Builder maxl(Long value) {
2280         return maxLength(value);
2281      }
2282
2283      /**
2284       * <mk>maxLength</mk> field.
2285       *
2286       * <p>
2287       * Same as {@link #maxLength(Long)} but takes in a string number.
2288       *
2289       * @param value
2290       *    The new value for this property.
2291       *    <br>Ignored if value is <jk>null</jk> or empty.
2292       * @return This object.
2293       */
2294      public Builder maxLength(String value) {
2295         maxLength = resolve(value, maxLength);
2296         return this;
2297      }
2298
2299      /**
2300       * Synonym for {@link #maxLength(String)}.
2301       *
2302       * @param value
2303       *    The new value for this property.
2304       * @return This object.
2305       */
2306      public Builder maxl(String value) {
2307         return maxLength(value);
2308      }
2309
2310      /**
2311       * <mk>minLength</mk> field.
2312       *
2313       * <p>
2314       * A string instance is valid against this keyword if its length is greater than, or equal to, the value of this keyword.
2315       * <br>The length of a string instance is defined as the number of its characters as defined by <a href='https://tools.ietf.org/html/rfc4627'>RFC 4627</a>.
2316       *
2317       * <p>
2318       * Only allowed for the following types: <js>"string"</js>.
2319       *
2320       * <p>
2321       * Applicable to the following Swagger schema objects:
2322       * <ul>
2323       *    <li><a class="doclink" href="https://swagger.io/specification/v2#parameterObject">Parameter</a>
2324       *    <li><a class="doclink" href="https://swagger.io/specification/v2#schemaObject">Schema</a>
2325       *    <li><a class="doclink" href="https://swagger.io/specification/v2#itemsObject">Items</a>
2326       *    <li><a class="doclink" href="https://swagger.io/specification/v2#headerObject">Header</a>
2327       * </ul>
2328       *
2329       * @param value
2330       *    The new value for this property.
2331       *    <br>Ignored if value is <jk>null</jk> or <c>-1</c>.
2332       * @return This object.
2333       */
2334      public Builder minLength(Long value) {
2335         minLength = resolve(value, minLength);
2336         return this;
2337      }
2338
2339      /**
2340       * Synonym for {@link #minLength(Long)}.
2341       *
2342       * @param value
2343       *    The new value for this property.
2344       * @return This object.
2345       */
2346      public Builder minl(Long value) {
2347         return minLength(value);
2348      }
2349
2350      /**
2351       * <mk>minLength</mk> field.
2352       *
2353       * <p>
2354       * Same as {@link #minLength(Long)} but takes in a string number.
2355       *
2356       * @param value
2357       *    The new value for this property.
2358       *    <br>Ignored if value is <jk>null</jk> or empty.
2359       * @return This object.
2360       */
2361      public Builder minLength(String value) {
2362         minLength = resolve(value, minLength);
2363         return this;
2364      }
2365
2366      /**
2367       * Synonym for {@link #minLength(String)}.
2368       *
2369       * @param value
2370       *    The new value for this property.
2371       * @return This object.
2372       */
2373      public Builder minl(String value) {
2374         return minLength(value);
2375      }
2376
2377      /**
2378       * <mk>pattern</mk> field.
2379       *
2380       * <p>
2381       * A string input is valid if it matches the specified regular expression pattern.
2382       *
2383       * <p>
2384       * Only allowed for the following types: <js>"string"</js>.
2385       *
2386       * <p>
2387       * Applicable to the following Swagger schema objects:
2388       * <ul>
2389       *    <li><a class="doclink" href="https://swagger.io/specification/v2#parameterObject">Parameter</a>
2390       *    <li><a class="doclink" href="https://swagger.io/specification/v2#schemaObject">Schema</a>
2391       *    <li><a class="doclink" href="https://swagger.io/specification/v2#itemsObject">Items</a>
2392       *    <li><a class="doclink" href="https://swagger.io/specification/v2#headerObject">Header</a>
2393       * </ul>
2394       *
2395       * @param value
2396       *    The new value for this property.
2397       *    <br>Ignored if value is <jk>null</jk> or empty.
2398       * @return This object.
2399       */
2400      public Builder pattern(String value) {
2401         try {
2402            if (isNotEmpty(value))
2403               this.pattern = Pattern.compile(value);
2404         } catch (Exception e) {
2405            throw new ContextRuntimeException(e, "Invalid value {0} passed in as pattern value.  Must be a valid regular expression.", value);
2406         }
2407         return this;
2408      }
2409
2410      /**
2411       * Synonym for {@link #pattern(String)}.
2412       *
2413       * @param value
2414       *    The new value for this property.
2415       * @return This object.
2416       */
2417      public Builder p(String value) {
2418         return pattern(value);
2419      }
2420
2421      /**
2422       * <mk>maxItems</mk> field.
2423       *
2424       * <p>
2425       * An array or collection is valid if its size is less than, or equal to, the value of this keyword.
2426       *
2427       * <p>
2428       * Only allowed for the following types: <js>"array"</js>.
2429       *
2430       * <p>
2431       * Applicable to the following Swagger schema objects:
2432       * <ul>
2433       *    <li><a class="doclink" href="https://swagger.io/specification/v2#parameterObject">Parameter</a>
2434       *    <li><a class="doclink" href="https://swagger.io/specification/v2#schemaObject">Schema</a>
2435       *    <li><a class="doclink" href="https://swagger.io/specification/v2#itemsObject">Items</a>
2436       *    <li><a class="doclink" href="https://swagger.io/specification/v2#headerObject">Header</a>
2437       * </ul>
2438       *
2439       * @param value
2440       *    The new value for this property.
2441       *    <br>Ignored if value is <jk>null</jk> or <c>-1</c>.
2442       * @return This object.
2443       */
2444      public Builder maxItems(Long value) {
2445         maxItems = resolve(value, maxItems);
2446         return this;
2447      }
2448
2449      /**
2450       * Synonym for {@link #maxItems(Long)}.
2451       *
2452       * @param value
2453       *    The new value for this property.
2454       * @return This object.
2455       */
2456      public Builder maxi(Long value) {
2457         return maxItems(value);
2458      }
2459
2460      /**
2461       * <mk>maxItems</mk> field.
2462       *
2463       * <p>
2464       * Same as {@link #maxItems(Long)} but takes in a string number.
2465       *
2466       * @param value
2467       *    The new value for this property.
2468       *    <br>Ignored if value is <jk>null</jk> or empty.
2469       * @return This object.
2470       */
2471      public Builder maxItems(String value) {
2472         maxItems = resolve(value, maxItems);
2473         return this;
2474      }
2475
2476      /**
2477       * Synonym for {@link #maxItems(String)}.
2478       *
2479       * @param value
2480       *    The new value for this property.
2481       * @return This object.
2482       */
2483      public Builder maxi(String value) {
2484         return maxItems(value);
2485      }
2486
2487      /**
2488       * <mk>minItems</mk> field.
2489       *
2490       * <p>
2491       * An array or collection is valid if its size is greater than, or equal to, the value of this keyword.
2492       *
2493       * <p>
2494       * Only allowed for the following types: <js>"array"</js>.
2495       *
2496       * <p>
2497       * Applicable to the following Swagger schema objects:
2498       * <ul>
2499       *    <li><a class="doclink" href="https://swagger.io/specification/v2#parameterObject">Parameter</a>
2500       *    <li><a class="doclink" href="https://swagger.io/specification/v2#schemaObject">Schema</a>
2501       *    <li><a class="doclink" href="https://swagger.io/specification/v2#itemsObject">Items</a>
2502       *    <li><a class="doclink" href="https://swagger.io/specification/v2#headerObject">Header</a>
2503       * </ul>
2504       *
2505       * @param value
2506       *    The new value for this property.
2507       *    <br>Ignored if value is <jk>null</jk> or <c>-1</c>.
2508       * @return This object.
2509       */
2510      public Builder minItems(Long value) {
2511         minItems = resolve(value, minItems);
2512         return this;
2513      }
2514
2515      /**
2516       * Synonym for {@link #minItems(Long)}.
2517       *
2518       * @param value
2519       *    The new value for this property.
2520       * @return This object.
2521       */
2522      public Builder mini(Long value) {
2523         return minItems(value);
2524      }
2525
2526      /**
2527       * <mk>minItems</mk> field.
2528       *
2529       * <p>
2530       * Same as {@link #minItems(Long)} but takes in a string number.
2531       *
2532       * @param value
2533       *    The new value for this property.
2534       *    <br>Ignored if value is <jk>null</jk> or empty.
2535       * @return This object.
2536       */
2537      public Builder minItems(String value) {
2538         minItems = resolve(value, minItems);
2539         return this;
2540      }
2541
2542      /**
2543       * Synonym for {@link #minItems(String)}.
2544       *
2545       * @param value
2546       *    The new value for this property.
2547       * @return This object.
2548       */
2549      public Builder mini(String value) {
2550         return minItems(value);
2551      }
2552
2553      /**
2554       * <mk>uniqueItems</mk> field.
2555       *
2556       * <p>
2557       * If <jk>true</jk>, the input validates successfully if all of its elements are unique.
2558       *
2559       * <p>
2560       * <br>If the parameter type is a subclass of {@link Set}, this validation is skipped (since a set can only contain unique items anyway).
2561       * <br>Otherwise, the collection or array is checked for duplicate items.
2562       *
2563       * <p>
2564       * Only allowed for the following types: <js>"array"</js>.
2565       *
2566       * <p>
2567       * Applicable to the following Swagger schema objects:
2568       * <ul>
2569       *    <li><a class="doclink" href="https://swagger.io/specification/v2#parameterObject">Parameter</a>
2570       *    <li><a class="doclink" href="https://swagger.io/specification/v2#schemaObject">Schema</a>
2571       *    <li><a class="doclink" href="https://swagger.io/specification/v2#itemsObject">Items</a>
2572       *    <li><a class="doclink" href="https://swagger.io/specification/v2#headerObject">Header</a>
2573       * </ul>
2574       *
2575       * @param value
2576       *    The new value for this property.
2577       *    <br>Ignored if value is <jk>null</jk>.
2578       * @return This object.
2579       */
2580      public Builder uniqueItems(Boolean value) {
2581         uniqueItems = resolve(value, uniqueItems);
2582         return this;
2583      }
2584
2585      /**
2586       * Synonym for {@link #uniqueItems(Boolean)}.
2587       *
2588       * @param value
2589       *    The new value for this property.
2590       * @return This object.
2591       */
2592      public Builder ui(Boolean value) {
2593         return uniqueItems(value);
2594      }
2595
2596      /**
2597       * <mk>uniqueItems</mk> field.
2598       *
2599       * <p>
2600       * Same as {@link #uniqueItems(Boolean)} but takes in a string boolean.
2601       *
2602       * @param value
2603       *    The new value for this property.
2604       *    <br>Ignored if value is <jk>null</jk> or empty..
2605       * @return This object.
2606       */
2607      public Builder uniqueItems(String value) {
2608         uniqueItems = resolve(value, uniqueItems);
2609         return this;
2610      }
2611
2612      /**
2613       * Synonym for {@link #uniqueItems(String)}.
2614       *
2615       * @param value
2616       *    The new value for this property.
2617       * @return This object.
2618       */
2619      public Builder ui(String value) {
2620         return uniqueItems(value);
2621      }
2622
2623      /**
2624       * <mk>uniqueItems</mk> field.
2625       *
2626       * <p>
2627       * Shortcut for calling <code>uniqueItems(<jk>true</jk>);</code>.
2628       *
2629       * @return This object.
2630       */
2631      public Builder uniqueItems() {
2632         return uniqueItems(true);
2633      }
2634
2635      /**
2636       * Synonym for {@link #uniqueItems()}.
2637       *
2638       * @return This object.
2639       */
2640      public Builder ui() {
2641         return uniqueItems();
2642      }
2643
2644      /**
2645       * <mk>skipIfEmpty</mk> field.
2646       *
2647       * <p>
2648       * Identifies whether an item should be skipped during serialization if it's empty.
2649       *
2650       * @param value
2651       *    The new value for this property.
2652       *    <br>Ignored if value is <jk>null</jk>.
2653       * @return This object.
2654       */
2655      public Builder skipIfEmpty(Boolean value) {
2656         skipIfEmpty = resolve(value, skipIfEmpty);
2657         return this;
2658      }
2659
2660      /**
2661       * Synonym for {@link #skipIfEmpty(Boolean)}.
2662       *
2663       * @param value
2664       *    The new value for this property.
2665       * @return This object.
2666       */
2667      public Builder sie(Boolean value) {
2668         return skipIfEmpty(value);
2669      }
2670
2671      /**
2672       * <mk>skipIfEmpty</mk> field.
2673       *
2674       * <p>
2675       * Same as {@link #skipIfEmpty(Boolean)} but takes in a string boolean.
2676       *
2677       * @param value
2678       *    The new value for this property.
2679       *    <br>Ignored if value is <jk>null</jk> or empty.
2680       * @return This object.
2681       */
2682      public Builder skipIfEmpty(String value) {
2683         skipIfEmpty = resolve(value, skipIfEmpty);
2684         return this;
2685      }
2686
2687      /**
2688       * Synonym for {@link #skipIfEmpty(String)}.
2689       *
2690       * @param value
2691       *    The new value for this property.
2692       * @return This object.
2693       */
2694      public Builder sie(String value) {
2695         return skipIfEmpty(value);
2696      }
2697
2698      /**
2699       * Identifies whether an item should be skipped if it's empty.
2700       *
2701       * <p>
2702       * Shortcut for calling <code>skipIfEmpty(<jk>true</jk>);</code>.
2703       *
2704       * @return This object.
2705       */
2706      public Builder skipIfEmpty() {
2707         return skipIfEmpty(true);
2708      }
2709
2710      /**
2711       * Synonym for {@link #skipIfEmpty()}.
2712       *
2713       * @return This object.
2714       */
2715      public Builder sie() {
2716         return skipIfEmpty();
2717      }
2718
2719      /**
2720       * <mk>enum</mk> field.
2721       *
2722       * <p>
2723       * If specified, the input validates successfully if it is equal to one of the elements in this array.
2724       *
2725       * <p>
2726       * Applicable to the following Swagger schema objects:
2727       * <ul>
2728       *    <li><a class="doclink" href="https://swagger.io/specification/v2#parameterObject">Parameter</a>
2729       *    <li><a class="doclink" href="https://swagger.io/specification/v2#schemaObject">Schema</a>
2730       *    <li><a class="doclink" href="https://swagger.io/specification/v2#itemsObject">Items</a>
2731       *    <li><a class="doclink" href="https://swagger.io/specification/v2#headerObject">Header</a>
2732       * </ul>
2733       *
2734       * @param value
2735       *    The new value for this property.
2736       *    <br>Ignored if value is <jk>null</jk> or an empty set.
2737       * @return This object.
2738       */
2739      public Builder _enum(Set<String> value) {
2740         if (value != null && ! value.isEmpty())
2741            this._enum = value;
2742         return this;
2743      }
2744
2745      /**
2746       * Synonym for {@link #_enum(Set)}.
2747       *
2748       * @param value
2749       *    The new value for this property.
2750       * @return This object.
2751       */
2752      public Builder e(Set<String> value) {
2753         return _enum(value);
2754      }
2755
2756      /**
2757       * <mk>_enum</mk> field.
2758       *
2759       * <p>
2760       * Same as {@link #_enum(Set)} but takes in a var-args array.
2761       *
2762       * @param values
2763       *    The new values for this property.
2764       *    <br>Ignored if value is empty.
2765       * @return This object.
2766       */
2767      public Builder _enum(String...values) {
2768         return _enum(set(values));
2769      }
2770
2771      /**
2772       * Synonym for {@link #_enum(String...)}.
2773       *
2774       * @param values
2775       *    The new values for this property.
2776       * @return This object.
2777       */
2778      public Builder e(String...values) {
2779         return _enum(values);
2780      }
2781
2782      /**
2783       * <mk>multipleOf</mk> field.
2784       *
2785       * <p>
2786       * A numeric instance is valid if the result of the division of the instance by this keyword's value is an integer.
2787       *
2788       * <p>
2789       * Only allowed for the following types: <js>"integer"</js>, <js>"number"</js>.
2790       *
2791       * <p>
2792       * Applicable to the following Swagger schema objects:
2793       * <ul>
2794       *    <li><a class="doclink" href="https://swagger.io/specification/v2#parameterObject">Parameter</a>
2795       *    <li><a class="doclink" href="https://swagger.io/specification/v2#schemaObject">Schema</a>
2796       *    <li><a class="doclink" href="https://swagger.io/specification/v2#itemsObject">Items</a>
2797       *    <li><a class="doclink" href="https://swagger.io/specification/v2#headerObject">Header</a>
2798       * </ul>
2799       *
2800       * @param value
2801       *    The new value for this property.
2802       *    <br>Ignored if value is <jk>null</jk>.
2803       * @return This object.
2804       */
2805      public Builder multipleOf(Number value) {
2806         if (value != null)
2807            this.multipleOf = value;
2808         return this;
2809      }
2810
2811      /**
2812       * Synonym for {@link #multipleOf(Number)}.
2813       *
2814       * @param value
2815       *    The new value for this property.
2816       * @return This object.
2817       */
2818      public Builder mo(Number value) {
2819         return multipleOf(value);
2820      }
2821
2822      /**
2823       * <mk>mapProperties</mk> field.
2824       *
2825       * <p>
2826       * Applicable to the following Swagger schema objects:
2827       * <ul>
2828       *    <li><a class="doclink" href="https://swagger.io/specification/v2#schemaObject">Schema</a>
2829       * </ul>
2830       *
2831       * @param value
2832       *    The new value for this property.
2833       *    <br>Ignored if value is <jk>null</jk> or <c>-1</c>.
2834       * @return This object.
2835       */
2836      public Builder maxProperties(Long value) {
2837         maxProperties = resolve(value, maxProperties);
2838         return this;
2839      }
2840
2841      /**
2842       * Synonym for {@link #maxProperties(Long)}.
2843       *
2844       * @param value
2845       *    The new value for this property.
2846       * @return This object.
2847       */
2848      public Builder maxp(Long value) {
2849         return maxProperties(value);
2850      }
2851
2852      /**
2853       * <mk>mapProperties</mk> field.
2854       *
2855       * <p>
2856       * Same as {@link #maxProperties(Long)} but takes in a string number.
2857       *
2858       * @param value
2859       *    The new value for this property.
2860       *    <br>Ignored if value is <jk>null</jk> or empty.
2861       * @return This object.
2862       */
2863      public Builder maxProperties(String value) {
2864         maxProperties = resolve(value, maxProperties);
2865         return this;
2866      }
2867
2868      /**
2869       * Synonym for {@link #maxProperties(String)}.
2870       *
2871       * @param value
2872       *    The new value for this property.
2873       * @return This object.
2874       */
2875      public Builder maxp(String value) {
2876         return maxProperties(value);
2877      }
2878
2879      /**
2880       * <mk>minProperties</mk> field.
2881       *
2882       * <p>
2883       * Applicable to the following Swagger schema objects:
2884       * <ul>
2885       *    <li><a class="doclink" href="https://swagger.io/specification/v2#schemaObject">Schema</a>
2886       * </ul>
2887       *
2888       * @param value
2889       *    The new value for this property.
2890       *    <br>Ignored if value is <jk>null</jk>.
2891       * @return This object.
2892       */
2893      public Builder minProperties(Long value) {
2894         minProperties = resolve(value, minProperties);
2895         return this;
2896      }
2897
2898      /**
2899       * Synonym for {@link #minProperties(Long)}.
2900       *
2901       * @param value
2902       *    The new value for this property.
2903       * @return This object.
2904       */
2905      public Builder minp(Long value) {
2906         return minProperties(value);
2907      }
2908
2909      /**
2910       * <mk>minProperties</mk> field.
2911       *
2912       * <p>
2913       * Same as {@link #minProperties(Long)} but takes in a string boolean.
2914       *
2915       * @param value
2916       *    The new value for this property.
2917       *    <br>Ignored if value is <jk>null</jk> or empty.
2918       * @return This object.
2919       */
2920      public Builder minProperties(String value) {
2921         minProperties = resolve(value, minProperties);
2922         return this;
2923      }
2924
2925      /**
2926       * Synonym for {@link #minProperties(String)}.
2927       *
2928       * @param value
2929       *    The new value for this property.
2930       * @return This object.
2931       */
2932      public Builder minp(String value) {
2933         return minProperties(value);
2934      }
2935
2936      /**
2937       * <mk>properties</mk> field.
2938       *
2939       * <p>
2940       * Applicable to the following Swagger schema objects:
2941       * <ul>
2942       *    <li><a class="doclink" href="https://swagger.io/specification/v2#schemaObject">Schema</a>
2943       * </ul>
2944       *
2945       * @param key
2946       * The property name.
2947       * @param value
2948       *    The new value for this property.
2949       *    <br>Ignored if value is <jk>null</jk>.
2950       * @return This object.
2951       */
2952      public Builder property(String key, Builder value) {
2953         if ( key != null && value != null) {
2954            if (properties == null)
2955               properties = map();
2956            properties.put(key, value);
2957         }
2958         return this;
2959      }
2960
2961      /**
2962       * <mk>properties</mk> field.
2963       *
2964       * <p>
2965       * Applicable to the following Swagger schema objects:
2966       * <ul>
2967       *    <li><a class="doclink" href="https://swagger.io/specification/v2#schemaObject">Schema</a>
2968       * </ul>
2969       *
2970       * @param key
2971       * The property name.
2972       * @param value
2973       *    The new value for this property.
2974       *    <br>Ignored if value is <jk>null</jk>.
2975       * @return This object.
2976       */
2977      public Builder property(String key, HttpPartSchema value) {
2978         if ( key != null && value != null) {
2979            if (properties == null)
2980               properties = map();
2981            properties.put(key, value);
2982         }
2983         return this;
2984      }
2985
2986      /**
2987       * Shortcut for <c>property(key, value)</c>.
2988       *
2989       * <p>
2990       * Applicable to the following Swagger schema objects:
2991       * <ul>
2992       *    <li><a class="doclink" href="https://swagger.io/specification/v2#schemaObject">Schema</a>
2993       * </ul>
2994       *
2995       * @param key
2996       * The property name.
2997       * @param value
2998       *    The new value for this property.
2999       *    <br>Ignored if value is <jk>null</jk>.
3000       * @return This object.
3001       */
3002      public Builder p(String key, Builder value) {
3003         return property(key, value);
3004      }
3005
3006      /**
3007       * Shortcut for <c>property(key, value)</c>.
3008       *
3009       * <p>
3010       * Applicable to the following Swagger schema objects:
3011       * <ul>
3012       *    <li><a class="doclink" href="https://swagger.io/specification/v2#schemaObject">Schema</a>
3013       * </ul>
3014       *
3015       * @param key
3016       * The property name.
3017       * @param value
3018       *    The new value for this property.
3019       *    <br>Ignored if value is <jk>null</jk>.
3020       * @return This object.
3021       */
3022      public Builder p(String key, HttpPartSchema value) {
3023         return property(key, value);
3024      }
3025
3026      private Builder properties(JsonMap value) {
3027         if (value != null)
3028            value.forEach((k,v) -> property(k, HttpPartSchema.create().apply((JsonMap)v)));
3029         return this;
3030      }
3031
3032      /**
3033       * <mk>additionalProperties</mk> field.
3034       *
3035       * <p>
3036       * Applicable to the following Swagger schema objects:
3037       * <ul>
3038       *    <li><a class="doclink" href="https://swagger.io/specification/v2#schemaObject">Schema</a>
3039       * </ul>
3040       *
3041       * @param value
3042       *    The new value for this property.
3043       *    <br>Ignored if value is <jk>null</jk> or empty.
3044       * @return This object.
3045       */
3046      public Builder additionalProperties(Builder value) {
3047         if (value != null)
3048            additionalProperties = value;
3049         return this;
3050      }
3051
3052      /**
3053       * <mk>additionalProperties</mk> field.
3054       *
3055       * <p>
3056       * Applicable to the following Swagger schema objects:
3057       * <ul>
3058       *    <li><a class="doclink" href="https://swagger.io/specification/v2#schemaObject">Schema</a>
3059       * </ul>
3060       *
3061       * @param value
3062       *    The new value for this property.
3063       *    <br>Ignored if value is <jk>null</jk> or empty.
3064       * @return This object.
3065       */
3066      public Builder additionalProperties(HttpPartSchema value) {
3067         if (value != null)
3068            additionalProperties = value;
3069         return this;
3070      }
3071
3072      /**
3073       * Shortcut for <c>additionalProperties(value)</c>
3074       *
3075       * <p>
3076       * Applicable to the following Swagger schema objects:
3077       * <ul>
3078       *    <li><a class="doclink" href="https://swagger.io/specification/v2#schemaObject">Schema</a>
3079       * </ul>
3080       *
3081       * @param value
3082       *    The new value for this property.
3083       *    <br>Ignored if value is <jk>null</jk> or empty.
3084       * @return This object.
3085       */
3086      public Builder ap(Builder value) {
3087         return additionalProperties(value);
3088      }
3089
3090      /**
3091       * Shortcut for <c>additionalProperties(value)</c>
3092       *
3093       * <p>
3094       * Applicable to the following Swagger schema objects:
3095       * <ul>
3096       *    <li><a class="doclink" href="https://swagger.io/specification/v2#schemaObject">Schema</a>
3097       * </ul>
3098       *
3099       * @param value
3100       *    The new value for this property.
3101       *    <br>Ignored if value is <jk>null</jk> or empty.
3102       * @return This object.
3103       */
3104      public Builder ap(HttpPartSchema value) {
3105         return additionalProperties(value);
3106      }
3107
3108      private Builder additionalProperties(JsonMap value) {
3109         if (value != null && ! value.isEmpty())
3110            additionalProperties = HttpPartSchema.create().apply(value);
3111         return this;
3112      }
3113
3114      /**
3115       * Identifies the part serializer to use for serializing this part.
3116       *
3117       * @param value
3118       *    The new value for this property.
3119       *    <br>Ignored if value is <jk>null</jk> or {@link HttpPartSerializer.Void}.
3120       * @return This object.
3121       */
3122      public Builder serializer(Class<? extends HttpPartSerializer> value) {
3123         if (isNotVoid(value))
3124            serializer = value;
3125         return this;
3126      }
3127
3128      /**
3129       * Identifies the part parser to use for parsing this part.
3130       *
3131       * @param value
3132       *    The new value for this property.
3133       *    <br>Ignored if value is <jk>null</jk> or {@link HttpPartParser.Void}.
3134       * @return This object.
3135       */
3136      public Builder parser(Class<? extends HttpPartParser> value) {
3137         if (isNotVoid(value))
3138            parser = value;
3139         return this;
3140      }
3141
3142      /**
3143       * Disables Swagger schema usage validation checking.
3144       *
3145       * @param value Specify <jk>true</jk> to prevent {@link ContextRuntimeException} from being thrown if invalid Swagger usage was detected.
3146       * @return This object.
3147       */
3148      public Builder noValidate(Boolean value) {
3149         if (value != null)
3150            this.noValidate = value;
3151         return this;
3152      }
3153
3154      /**
3155       * Disables Swagger schema usage validation checking.
3156       *
3157       * <p>
3158       * Shortcut for calling <code>noValidate(<jk>true</jk>);</code>.
3159       *
3160       * @return This object.
3161       */
3162      public Builder noValidate() {
3163         return noValidate(true);
3164      }
3165
3166      private Boolean resolve(String newValue, Boolean oldValue) {
3167         return isEmpty(newValue) ? oldValue : Boolean.valueOf(newValue);
3168      }
3169
3170      private Boolean resolve(Boolean newValue, Boolean oldValue) {
3171         return newValue == null ? oldValue : newValue;
3172      }
3173
3174      private Long resolve(String newValue, Long oldValue) {
3175         return isEmpty(newValue) ? oldValue : Long.parseLong(newValue);
3176      }
3177
3178      private Long resolve(Long newValue, Long oldValue) {
3179         return (newValue == null || newValue == -1) ? oldValue : newValue;
3180      }
3181
3182      private Set<String> toSet(String[]...s) {
3183         return HttpPartSchema.toSet(s);
3184      }
3185
3186      private Number toNumber(String...s) {
3187         return HttpPartSchema.toNumber(s);
3188      }
3189
3190      private Long firstNmo(Long...l) {
3191         for (Long ll : l)
3192            if (ll != null && ll != -1)
3193               return ll;
3194         return null;
3195      }
3196
3197      private String joinnlOrNull(String[]...s) {
3198         for (String[] ss : s)
3199            if (ss.length > 0)
3200               return joinnl(ss);
3201         return null;
3202      }
3203   }
3204
3205   //-------------------------------------------------------------------------------------------------------------------
3206   // Instance
3207   //-------------------------------------------------------------------------------------------------------------------
3208
3209   final String name;
3210   final String _default;
3211   final Set<String> _enum;
3212   final Map<String,HttpPartSchema> properties;
3213   final boolean allowEmptyValue, exclusiveMaximum, exclusiveMinimum, required, uniqueItems, skipIfEmpty;
3214   final HttpPartCollectionFormat collectionFormat;
3215   final HttpPartDataType type;
3216   final HttpPartFormat format;
3217   final Pattern pattern;
3218   final HttpPartSchema items, additionalProperties;
3219   final Number maximum, minimum, multipleOf;
3220   final Long maxLength, minLength, maxItems, minItems, maxProperties, minProperties;
3221   final Class<? extends HttpPartParser> parser;
3222   final Class<? extends HttpPartSerializer> serializer;
3223   final ClassMeta<?> parsedType;
3224
3225   HttpPartSchema(Builder b) {
3226      this.name = b.name;
3227      this._default = b._default;
3228      this._enum = copy(b._enum);
3229      this.properties = build(b.properties, b.noValidate);
3230      this.allowEmptyValue = resolve(b.allowEmptyValue);
3231      this.exclusiveMaximum = resolve(b.exclusiveMaximum);
3232      this.exclusiveMinimum = resolve(b.exclusiveMinimum);
3233      this.required = resolve(b.required);
3234      this.uniqueItems = resolve(b.uniqueItems);
3235      this.skipIfEmpty = resolve(b.skipIfEmpty);
3236      this.collectionFormat = b.collectionFormat;
3237      this.type = b.type;
3238      this.format = b.format;
3239      this.pattern = b.pattern;
3240      this.items = build(b.items, b.noValidate);
3241      this.additionalProperties = build(b.additionalProperties, b.noValidate);
3242      this.maximum = b.maximum;
3243      this.minimum = b.minimum;
3244      this.multipleOf = b.multipleOf;
3245      this.maxItems = b.maxItems;
3246      this.maxLength = b.maxLength;
3247      this.maxProperties = b.maxProperties;
3248      this.minItems = b.minItems;
3249      this.minLength = b.minLength;
3250      this.minProperties = b.minProperties;
3251      this.parser = b.parser;
3252      this.serializer = b.serializer;
3253
3254      // Calculate parse type
3255      Class<?> parsedType = Object.class;
3256      if (type == ARRAY) {
3257         if (items != null)
3258            parsedType = Array.newInstance(items.parsedType.getInnerClass(), 0).getClass();
3259      } else if (type == BOOLEAN) {
3260         parsedType = Boolean.class;
3261      } else if (type == INTEGER) {
3262         if (format == INT64)
3263            parsedType = Long.class;
3264         else
3265            parsedType = Integer.class;
3266      } else if (type == NUMBER) {
3267         if (format == DOUBLE)
3268            parsedType = Double.class;
3269         else
3270            parsedType = Float.class;
3271      } else if (type == STRING) {
3272         if (format == BYTE || format == BINARY || format == BINARY_SPACED)
3273            parsedType = byte[].class;
3274         else if (format == DATE || format == DATE_TIME)
3275            parsedType = Calendar.class;
3276         else
3277            parsedType = String.class;
3278      }
3279      this.parsedType = BeanContext.DEFAULT.getClassMeta(parsedType);
3280
3281      if (b.noValidate)
3282         return;
3283
3284      // Validation.
3285      List<String> errors = list();
3286      ListBuilder<String> notAllowed = listBuilder(String.class);
3287      boolean invalidFormat = false;
3288      switch (type) {
3289         case STRING: {
3290            notAllowed
3291               .addIf(properties != null, "properties")
3292               .addIf(additionalProperties != null, "additionalProperties")
3293               .addIf(exclusiveMaximum, "exclusiveMaximum")
3294               .addIf(exclusiveMinimum, "exclusiveMinimum")
3295               .addIf(uniqueItems, "uniqueItems")
3296               .addIf(collectionFormat != HttpPartCollectionFormat.NO_COLLECTION_FORMAT, "collectionFormat")
3297               .addIf(items != null, "items")
3298               .addIf(maximum != null, "maximum")
3299               .addIf(minimum != null, "minimum")
3300               .addIf(multipleOf != null, "multipleOf")
3301               .addIf(maxItems != null, "maxItems")
3302               .addIf(minItems != null, "minItems")
3303               .addIf(minProperties != null, "minProperties");
3304            invalidFormat = ! format.isOneOf(HttpPartFormat.BYTE, HttpPartFormat.BINARY, HttpPartFormat.BINARY_SPACED, HttpPartFormat.DATE, HttpPartFormat.DATE_TIME, HttpPartFormat.PASSWORD, HttpPartFormat.UON, HttpPartFormat.NO_FORMAT);
3305            break;
3306         }
3307         case ARRAY: {
3308            notAllowed.addIf(properties != null, "properties")
3309               .addIf(additionalProperties != null, "additionalProperties")
3310               .addIf(exclusiveMaximum, "exclusiveMaximum")
3311               .addIf(exclusiveMinimum, "exclusiveMinimum")
3312               .addIf(pattern != null, "pattern")
3313               .addIf(maximum != null, "maximum")
3314               .addIf(minimum != null, "minimum")
3315               .addIf(multipleOf != null, "multipleOf")
3316               .addIf(maxLength != null, "maxLength")
3317               .addIf(minLength != null, "minLength")
3318               .addIf(maxProperties != null, "maxProperties")
3319               .addIf(minProperties != null, "minProperties");
3320            invalidFormat = ! format.isOneOf(HttpPartFormat.NO_FORMAT, HttpPartFormat.UON);
3321            break;
3322         }
3323         case BOOLEAN: {
3324            notAllowed.addIf(! _enum.isEmpty(), "_enum")
3325               .addIf(properties != null, "properties")
3326               .addIf(additionalProperties != null, "additionalProperties")
3327               .addIf(exclusiveMaximum, "exclusiveMaximum")
3328               .addIf(exclusiveMinimum, "exclusiveMinimum")
3329               .addIf(uniqueItems, "uniqueItems")
3330               .addIf(collectionFormat != HttpPartCollectionFormat.NO_COLLECTION_FORMAT, "collectionFormat")
3331               .addIf(pattern != null, "pattern")
3332               .addIf(items != null, "items")
3333               .addIf(maximum != null, "maximum")
3334               .addIf(minimum != null, "minimum")
3335               .addIf(multipleOf != null, "multipleOf")
3336               .addIf(maxItems != null, "maxItems")
3337               .addIf(maxLength != null, "maxLength")
3338               .addIf(maxProperties != null, "maxProperties")
3339               .addIf(minItems != null, "minItems")
3340               .addIf(minLength != null, "minLength")
3341               .addIf(minProperties != null, "minProperties");
3342            invalidFormat = ! format.isOneOf(HttpPartFormat.NO_FORMAT, HttpPartFormat.UON);
3343            break;
3344         }
3345         case FILE: {
3346            break;
3347         }
3348         case INTEGER: {
3349            notAllowed.addIf(properties != null, "properties")
3350               .addIf(additionalProperties != null, "additionalProperties")
3351               .addIf(uniqueItems, "uniqueItems")
3352               .addIf(collectionFormat != HttpPartCollectionFormat.NO_COLLECTION_FORMAT, "collectionFormat")
3353               .addIf(pattern != null, "pattern")
3354               .addIf(items != null, "items")
3355               .addIf(maxItems != null, "maxItems")
3356               .addIf(maxLength != null, "maxLength")
3357               .addIf(maxProperties != null, "maxProperties")
3358               .addIf(minItems != null, "minItems")
3359               .addIf(minLength != null, "minLength")
3360               .addIf(minProperties != null, "minProperties");
3361            invalidFormat = ! format.isOneOf(HttpPartFormat.NO_FORMAT, HttpPartFormat.UON, HttpPartFormat.INT32, HttpPartFormat.INT64);
3362            break;
3363         }
3364         case NUMBER: {
3365            notAllowed.addIf(properties != null, "properties")
3366               .addIf(additionalProperties != null, "additionalProperties")
3367               .addIf(uniqueItems, "uniqueItems")
3368               .addIf(collectionFormat != HttpPartCollectionFormat.NO_COLLECTION_FORMAT, "collectionFormat")
3369               .addIf(pattern != null, "pattern")
3370               .addIf(items != null, "items")
3371               .addIf(maxItems != null, "maxItems")
3372               .addIf(maxLength != null, "maxLength")
3373               .addIf(maxProperties != null, "maxProperties")
3374               .addIf(minItems != null, "minItems")
3375               .addIf(minLength != null, "minLength")
3376               .addIf(minProperties != null, "minProperties");
3377            invalidFormat = ! format.isOneOf(HttpPartFormat.NO_FORMAT, HttpPartFormat.UON, HttpPartFormat.FLOAT, HttpPartFormat.DOUBLE);
3378            break;
3379         }
3380         case OBJECT: {
3381            notAllowed.addIf(exclusiveMaximum, "exclusiveMaximum")
3382               .addIf(exclusiveMinimum, "exclusiveMinimum")
3383               .addIf(uniqueItems, "uniqueItems")
3384               .addIf(pattern != null, "pattern")
3385               .addIf(items != null, "items")
3386               .addIf(maximum != null, "maximum")
3387               .addIf(minimum != null, "minimum")
3388               .addIf(multipleOf != null, "multipleOf")
3389               .addIf(maxItems != null, "maxItems")
3390               .addIf(maxLength != null, "maxLength")
3391               .addIf(minItems != null, "minItems")
3392               .addIf(minLength != null, "minLength");
3393            invalidFormat = ! format.isOneOf(HttpPartFormat.NO_FORMAT);
3394            break;
3395         }
3396         default:
3397            break;
3398      }
3399
3400      List<String> notAllowed2 = notAllowed.build();
3401      if (! notAllowed2.isEmpty())
3402         errors.add("Attributes not allow for type='"+type+"': " + StringUtils.join(notAllowed2, ","));
3403      if (invalidFormat)
3404         errors.add("Invalid format for type='"+type+"': '"+format+"'");
3405      if (exclusiveMaximum && maximum == null)
3406         errors.add("Cannot specify exclusiveMaximum with maximum.");
3407      if (exclusiveMinimum && minimum == null)
3408         errors.add("Cannot specify exclusiveMinimum with minimum.");
3409      if (required && _default != null)
3410         errors.add("Cannot specify a default value on a required value.");
3411      if (minLength != null && maxLength != null && maxLength < minLength)
3412         errors.add("maxLength cannot be less than minLength.");
3413      if (minimum != null && maximum != null && maximum.doubleValue() < minimum.doubleValue())
3414         errors.add("maximum cannot be less than minimum.");
3415      if (minItems != null && maxItems != null && maxItems < minItems)
3416         errors.add("maxItems cannot be less than minItems.");
3417      if (minProperties != null && maxProperties != null && maxProperties < minProperties)
3418         errors.add("maxProperties cannot be less than minProperties.");
3419      if (minLength != null && minLength < 0)
3420         errors.add("minLength cannot be less than zero.");
3421      if (maxLength != null && maxLength < 0)
3422         errors.add("maxLength cannot be less than zero.");
3423      if (minItems != null && minItems < 0)
3424         errors.add("minItems cannot be less than zero.");
3425      if (maxItems != null && maxItems < 0)
3426         errors.add("maxItems cannot be less than zero.");
3427      if (minProperties != null && minProperties < 0)
3428         errors.add("minProperties cannot be less than zero.");
3429      if (maxProperties != null && maxProperties < 0)
3430         errors.add("maxProperties cannot be less than zero.");
3431      if (type == ARRAY && items != null && items.getType() == OBJECT && (format != UON && format != HttpPartFormat.NO_FORMAT))
3432         errors.add("Cannot define an array of objects unless array format is 'uon'.");
3433
3434      if (! errors.isEmpty())
3435         throw new ContextRuntimeException("Schema specification errors: \n\t" + join(errors, "\n\t"), new Object[0]);
3436   }
3437
3438   /**
3439    * Returns the default parsed type for this schema.
3440    *
3441    * @return The default parsed type for this schema.  Never <jk>null</jk>.
3442    */
3443   public ClassMeta<?> getParsedType() {
3444      return parsedType;
3445   }
3446
3447   /**
3448    * Returns the name of the object described by this schema, for example the query or form parameter name.
3449    *
3450    * @return The name, or <jk>null</jk> if not specified.
3451    * @see HttpPartSchema.Builder#name(String)
3452    */
3453   public String getName() {
3454      return name;
3455   }
3456
3457   /**
3458    * Returns the <c>type</c> field of this schema.
3459    *
3460    * @return The <c>type</c> field of this schema, or <jk>null</jk> if not specified.
3461    * @see HttpPartSchema.Builder#type(String)
3462    */
3463   public HttpPartDataType getType() {
3464      return type;
3465   }
3466
3467   /**
3468    * Returns the <c>type</c> field of this schema.
3469    *
3470    * @param cm
3471    *    The class meta of the object.
3472    *    <br>Used to auto-detect the type if the type was not specified.
3473    * @return The format field of this schema, or <jk>null</jk> if not specified.
3474    * @see HttpPartSchema.Builder#format(String)
3475    */
3476   public HttpPartDataType getType(ClassMeta<?> cm) {
3477      if (type != HttpPartDataType.NO_TYPE)
3478         return type;
3479      if (cm.isTemporal() || cm.isDateOrCalendar())
3480         return HttpPartDataType.STRING;
3481      if (cm.isNumber()) {
3482         if (cm.isDecimal())
3483            return HttpPartDataType.NUMBER;
3484         return HttpPartDataType.INTEGER;
3485      }
3486      if (cm.isBoolean())
3487         return HttpPartDataType.BOOLEAN;
3488      if (cm.isMapOrBean())
3489         return HttpPartDataType.OBJECT;
3490      if (cm.isCollectionOrArray())
3491         return HttpPartDataType.ARRAY;
3492      return HttpPartDataType.STRING;
3493   }
3494
3495   /**
3496    * Returns the <c>default</c> field of this schema.
3497    *
3498    * @return The default value for this schema, or <jk>null</jk> if not specified.
3499    * @see HttpPartSchema.Builder#_default(String)
3500    */
3501   public String getDefault() {
3502      return _default;
3503   }
3504
3505   /**
3506    * Returns the <c>collectionFormat</c> field of this schema.
3507    *
3508    * @return The <c>collectionFormat</c> field of this schema, or <jk>null</jk> if not specified.
3509    * @see HttpPartSchema.Builder#collectionFormat(String)
3510    */
3511   public HttpPartCollectionFormat getCollectionFormat() {
3512      return collectionFormat;
3513   }
3514
3515   /**
3516    * Returns the <c>format</c> field of this schema.
3517    *
3518    * @see HttpPartSchema.Builder#format(String)
3519    * @return The <c>format</c> field of this schema, or <jk>null</jk> if not specified.
3520    */
3521   public HttpPartFormat getFormat() {
3522      return format;
3523   }
3524
3525   /**
3526    * Returns the <c>format</c> field of this schema.
3527    *
3528    * @param cm
3529    *    The class meta of the object.
3530    *    <br>Used to auto-detect the format if the format was not specified.
3531    * @return The <c>format</c> field of this schema, or <jk>null</jk> if not specified.
3532    * @see HttpPartSchema.Builder#format(String)
3533    */
3534   public HttpPartFormat getFormat(ClassMeta<?> cm) {
3535      if (format != HttpPartFormat.NO_FORMAT)
3536         return format;
3537      if (cm.isNumber()) {
3538         if (cm.isDecimal()) {
3539            if (cm.isDouble())
3540               return HttpPartFormat.DOUBLE;
3541            return HttpPartFormat.FLOAT;
3542         }
3543         if (cm.isLong())
3544            return HttpPartFormat.INT64;
3545         return HttpPartFormat.INT32;
3546      }
3547      return format;
3548   }
3549
3550   /**
3551    * Returns the <c>maximum</c> field of this schema.
3552    *
3553    * @return The schema for child items of the object represented by this schema, or <jk>null</jk> if not defined.
3554    * @see HttpPartSchema.Builder#items(HttpPartSchema.Builder)
3555    */
3556   public HttpPartSchema getItems() {
3557      return items;
3558   }
3559
3560   /**
3561    * Returns the <c>maximum</c> field of this schema.
3562    *
3563    * @return The <c>maximum</c> field of this schema, or <jk>null</jk> if not specified.
3564    * @see HttpPartSchema.Builder#maximum(Number)
3565    */
3566   public Number getMaximum() {
3567      return maximum;
3568   }
3569
3570   /**
3571    * Returns the <c>minimum</c> field of this schema.
3572    *
3573    * @return The <c>minimum</c> field of this schema, or <jk>null</jk> if not specified.
3574    * @see HttpPartSchema.Builder#minimum(Number)
3575    */
3576   public Number getMinimum() {
3577      return minimum;
3578   }
3579
3580   /**
3581    * Returns the <c>xxx</c> field of this schema.
3582    *
3583    * @return The <c>xxx</c> field of this schema, or <jk>null</jk> if not specified.
3584    * @see HttpPartSchema.Builder#multipleOf(Number)
3585    */
3586   public Number getMultipleOf() {
3587      return multipleOf;
3588   }
3589
3590   /**
3591    * Returns the <c>xxx</c> field of this schema.
3592    *
3593    * @return The <c>xxx</c> field of this schema, or <jk>null</jk> if not specified.
3594    * @see HttpPartSchema.Builder#pattern(String)
3595    */
3596   public Pattern getPattern() {
3597      return pattern;
3598   }
3599
3600   /**
3601    * Returns the <c>xxx</c> field of this schema.
3602    *
3603    * @return The <c>xxx</c> field of this schema, or <jk>null</jk> if not specified.
3604    * @see HttpPartSchema.Builder#maxLength(Long)
3605    */
3606   public Long getMaxLength() {
3607      return maxLength;
3608   }
3609
3610   /**
3611    * Returns the <c>xxx</c> field of this schema.
3612    *
3613    * @return The <c>xxx</c> field of this schema, or <jk>null</jk> if not specified.
3614    * @see HttpPartSchema.Builder#minLength(Long)
3615    */
3616   public Long getMinLength() {
3617      return minLength;
3618   }
3619
3620   /**
3621    * Returns the <c>xxx</c> field of this schema.
3622    *
3623    * @return The <c>xxx</c> field of this schema, or <jk>null</jk> if not specified.
3624    * @see HttpPartSchema.Builder#maxItems(Long)
3625    */
3626   public Long getMaxItems() {
3627      return maxItems;
3628   }
3629
3630   /**
3631    * Returns the <c>xxx</c> field of this schema.
3632    *
3633    * @return The <c>xxx</c> field of this schema, or <jk>null</jk> if not specified.
3634    * @see HttpPartSchema.Builder#minItems(Long)
3635    */
3636   public Long getMinItems() {
3637      return minItems;
3638   }
3639
3640   /**
3641    * Returns the <c>xxx</c> field of this schema.
3642    *
3643    * @return The <c>xxx</c> field of this schema, or <jk>null</jk> if not specified.
3644    * @see HttpPartSchema.Builder#maxProperties(Long)
3645    */
3646   public Long getMaxProperties() {
3647      return maxProperties;
3648   }
3649
3650   /**
3651    * Returns the <c>xxx</c> field of this schema.
3652    *
3653    * @return The <c>xxx</c> field of this schema, or <jk>null</jk> if not specified.
3654    * @see HttpPartSchema.Builder#minProperties(Long)
3655    */
3656   public Long getMinProperties() {
3657      return minProperties;
3658   }
3659
3660   /**
3661    * Returns the <c>exclusiveMaximum</c> field of this schema.
3662    *
3663    * @return The <c>exclusiveMaximum</c> field of this schema.
3664    * @see HttpPartSchema.Builder#exclusiveMaximum(Boolean)
3665    */
3666   public boolean isExclusiveMaximum() {
3667      return exclusiveMaximum;
3668   }
3669
3670   /**
3671    * Returns the <c>exclusiveMinimum</c> field of this schema.
3672    *
3673    * @return The <c>exclusiveMinimum</c> field of this schema.
3674    * @see HttpPartSchema.Builder#exclusiveMinimum(Boolean)
3675    */
3676   public boolean isExclusiveMinimum() {
3677      return exclusiveMinimum;
3678   }
3679
3680   /**
3681    * Returns the <c>uniqueItems</c> field of this schema.
3682    *
3683    * @return The <c>uniqueItems</c> field of this schema.
3684    * @see HttpPartSchema.Builder#uniqueItems(Boolean)
3685    */
3686   public boolean isUniqueItems() {
3687      return uniqueItems;
3688   }
3689
3690   /**
3691    * Returns the <c>required</c> field of this schema.
3692    *
3693    * @return The <c>required</c> field of this schema.
3694    * @see HttpPartSchema.Builder#required(Boolean)
3695    */
3696   public boolean isRequired() {
3697      return required;
3698   }
3699
3700   /**
3701    * Returns the <c>skipIfEmpty</c> field of this schema.
3702    *
3703    * @return The <c>skipIfEmpty</c> field of this schema.
3704    * @see HttpPartSchema.Builder#skipIfEmpty(Boolean)
3705    */
3706   public boolean isSkipIfEmpty() {
3707      return skipIfEmpty;
3708   }
3709
3710   /**
3711    * Returns the <c>allowEmptyValue</c> field of this schema.
3712    *
3713    * @return The <c>skipIfEmpty</c> field of this schema.
3714    * @see HttpPartSchema.Builder#skipIfEmpty(Boolean)
3715    */
3716   public boolean isAllowEmptyValue() {
3717      return allowEmptyValue;
3718   }
3719
3720   /**
3721    * Returns the <c>enum</c> field of this schema.
3722    *
3723    * @return The <c>enum</c> field of this schema, or <jk>null</jk> if not specified.
3724    * @see HttpPartSchema.Builder#_enum(Set)
3725    */
3726   public Set<String> getEnum() {
3727      return _enum;
3728   }
3729
3730   /**
3731    * Returns the <c>parser</c> field of this schema.
3732    *
3733    * @return The <c>parser</c> field of this schema, or <jk>null</jk> if not specified.
3734    * @see HttpPartSchema.Builder#parser(Class)
3735    */
3736   public Class<? extends HttpPartParser> getParser() {
3737      return parser;
3738   }
3739
3740   /**
3741    * Returns the <c>serializer</c> field of this schema.
3742    *
3743    * @return The <c>serializer</c> field of this schema, or <jk>null</jk> if not specified.
3744    * @see HttpPartSchema.Builder#serializer(Class)
3745    */
3746   public Class<? extends HttpPartSerializer> getSerializer() {
3747      return serializer;
3748   }
3749
3750   /**
3751    * Throws a {@link ParseException} if the specified pre-parsed input does not validate against this schema.
3752    *
3753    * @param in The input.
3754    * @return The same object passed in.
3755    * @throws SchemaValidationException if the specified pre-parsed input does not validate against this schema.
3756    */
3757   public String validateInput(String in) throws SchemaValidationException {
3758      if (! isValidRequired(in))
3759         throw new SchemaValidationException("No value specified.");
3760      if (in != null) {
3761         if (! isValidAllowEmpty(in))
3762            throw new SchemaValidationException("Empty value not allowed.");
3763         if (! isValidPattern(in))
3764            throw new SchemaValidationException("Value does not match expected pattern.  Must match pattern: {0}", pattern.pattern());
3765         if (! isValidEnum(in))
3766            throw new SchemaValidationException("Value does not match one of the expected values.  Must be one of the following:  {0}", cdl(_enum));
3767         if (! isValidMaxLength(in))
3768            throw new SchemaValidationException("Maximum length of value exceeded.");
3769         if (! isValidMinLength(in))
3770            throw new SchemaValidationException("Minimum length of value not met.");
3771      }
3772      return in;
3773   }
3774
3775   /**
3776    * Throws a {@link ParseException} if the specified parsed output does not validate against this schema.
3777    *
3778    * @param <T> The return type.
3779    * @param o The parsed output.
3780    * @param bc The bean context used to detect POJO types.
3781    * @return The same object passed in.
3782    * @throws SchemaValidationException if the specified parsed output does not validate against this schema.
3783    */
3784   public <T> T validateOutput(T o, BeanContext bc) throws SchemaValidationException {
3785      if (o == null) {
3786         if (! isValidRequired(o))
3787            throw new SchemaValidationException("Required value not provided.");
3788         return o;
3789      }
3790      ClassMeta<?> cm = bc.getClassMetaForObject(o);
3791      switch (getType(cm)) {
3792         case ARRAY: {
3793            if (cm.isArray()) {
3794               if (! isValidMinItems(o))
3795                  throw new SchemaValidationException("Minimum number of items not met.");
3796               if (! isValidMaxItems(o))
3797                  throw new SchemaValidationException("Maximum number of items exceeded.");
3798               if (! isValidUniqueItems(o))
3799                  throw new SchemaValidationException("Duplicate items not allowed.");
3800               HttpPartSchema items = getItems();
3801               if (items != null)
3802                  for (int i = 0; i < Array.getLength(o); i++)
3803                     items.validateOutput(Array.get(o, i), bc);
3804            } else if (cm.isCollection()) {
3805               Collection<?> c = (Collection<?>)o;
3806               if (! isValidMinItems(c))
3807                  throw new SchemaValidationException("Minimum number of items not met.");
3808               if (! isValidMaxItems(c))
3809                  throw new SchemaValidationException("Maximum number of items exceeded.");
3810               if (! isValidUniqueItems(c))
3811                  throw new SchemaValidationException("Duplicate items not allowed.");
3812               HttpPartSchema items = getItems();
3813               if (items != null)
3814                  c.forEach(x -> items.validateOutput(x, bc));
3815            }
3816            break;
3817         }
3818         case INTEGER: {
3819            if (cm.isNumber()) {
3820               Number n = (Number)o;
3821               if (! isValidMinimum(n))
3822                  throw new SchemaValidationException("Minimum value not met.");
3823               if (! isValidMaximum(n))
3824                  throw new SchemaValidationException("Maximum value exceeded.");
3825               if (! isValidMultipleOf(n))
3826                  throw new SchemaValidationException("Multiple-of not met.");
3827            }
3828            break;
3829         }
3830         case NUMBER: {
3831            if (cm.isNumber()) {
3832               Number n = (Number)o;
3833               if (! isValidMinimum(n))
3834                  throw new SchemaValidationException("Minimum value not met.");
3835               if (! isValidMaximum(n))
3836                  throw new SchemaValidationException("Maximum value exceeded.");
3837               if (! isValidMultipleOf(n))
3838                  throw new SchemaValidationException("Multiple-of not met.");
3839            }
3840            break;
3841         }
3842         case OBJECT: {
3843            if (cm.isMapOrBean()) {
3844               Map<?,?> m = cm.isMap() ? (Map<?,?>)o : bc.toBeanMap(o);
3845               if (! isValidMinProperties(m))
3846                  throw new SchemaValidationException("Minimum number of properties not met.");
3847               if (! isValidMaxProperties(m))
3848                  throw new SchemaValidationException("Maximum number of properties exceeded.");
3849               m.forEach((k,v) -> {
3850                  String key = k.toString();
3851                  HttpPartSchema s2 = getProperty(key);
3852                  if (s2 != null)
3853                     s2.validateOutput(v, bc);
3854               });
3855            } else if (cm.isBean()) {
3856
3857            }
3858            break;
3859         }
3860         case BOOLEAN:
3861         case FILE:
3862         case STRING:
3863         case NO_TYPE:
3864            break;
3865      }
3866      return o;
3867   }
3868
3869   //-----------------------------------------------------------------------------------------------------------------
3870   // Helper methods.
3871   //-----------------------------------------------------------------------------------------------------------------
3872
3873   private boolean isValidRequired(Object x) {
3874      return x != null || ! required;
3875   }
3876
3877   private boolean isValidMinProperties(Map<?,?> x) {
3878      return minProperties == null || x.size() >= minProperties;
3879   }
3880
3881   private boolean isValidMaxProperties(Map<?,?> x) {
3882      return maxProperties == null || x.size() <= maxProperties;
3883   }
3884
3885   private boolean isValidMinimum(Number x) {
3886      if (x instanceof Integer || x instanceof AtomicInteger)
3887         return minimum == null || x.intValue() > minimum.intValue() || (x.intValue() == minimum.intValue() && (! exclusiveMinimum));
3888      if (x instanceof Short || x instanceof Byte)
3889         return minimum == null || x.shortValue() > minimum.shortValue() || (x.intValue() == minimum.shortValue() && (! exclusiveMinimum));
3890      if (x instanceof Long || x instanceof AtomicLong || x instanceof BigInteger)
3891         return minimum == null || x.longValue() > minimum.longValue() || (x.intValue() == minimum.longValue() && (! exclusiveMinimum));
3892      if (x instanceof Float)
3893         return minimum == null || x.floatValue() > minimum.floatValue() || (x.floatValue() == minimum.floatValue() && (! exclusiveMinimum));
3894      if (x instanceof Double || x instanceof BigDecimal)
3895         return minimum == null || x.doubleValue() > minimum.doubleValue() || (x.doubleValue() == minimum.doubleValue() && (! exclusiveMinimum));
3896      return true;
3897   }
3898
3899   private boolean isValidMaximum(Number x) {
3900      if (x instanceof Integer || x instanceof AtomicInteger)
3901         return maximum == null || x.intValue() < maximum.intValue() || (x.intValue() == maximum.intValue() && (! exclusiveMaximum));
3902      if (x instanceof Short || x instanceof Byte)
3903         return maximum == null || x.shortValue() < maximum.shortValue() || (x.intValue() == maximum.shortValue() && (! exclusiveMaximum));
3904      if (x instanceof Long || x instanceof AtomicLong || x instanceof BigInteger)
3905         return maximum == null || x.longValue() < maximum.longValue() || (x.intValue() == maximum.longValue() && (! exclusiveMaximum));
3906      if (x instanceof Float)
3907         return maximum == null || x.floatValue() < maximum.floatValue() || (x.floatValue() == maximum.floatValue() && (! exclusiveMaximum));
3908      if (x instanceof Double || x instanceof BigDecimal)
3909         return maximum == null || x.doubleValue() < maximum.doubleValue() || (x.doubleValue() == maximum.doubleValue() && (! exclusiveMaximum));
3910      return true;
3911   }
3912
3913   private boolean isValidMultipleOf(Number x) {
3914      if (x instanceof Integer || x instanceof AtomicInteger)
3915         return multipleOf == null || x.intValue() % multipleOf.intValue() == 0;
3916      if (x instanceof Short || x instanceof Byte)
3917         return multipleOf == null || x.shortValue() % multipleOf.shortValue() == 0;
3918      if (x instanceof Long || x instanceof AtomicLong || x instanceof BigInteger)
3919         return multipleOf == null || x.longValue() % multipleOf.longValue() == 0;
3920      if (x instanceof Float)
3921         return multipleOf == null || x.floatValue() % multipleOf.floatValue() == 0;
3922      if (x instanceof Double || x instanceof BigDecimal)
3923         return multipleOf == null || x.doubleValue() % multipleOf.doubleValue() == 0;
3924      return true;
3925   }
3926
3927   private boolean isValidAllowEmpty(String x) {
3928      return allowEmptyValue || isNotEmpty(x);
3929   }
3930
3931   private boolean isValidPattern(String x) {
3932      return pattern == null || pattern.matcher(x).matches();
3933   }
3934
3935   private boolean isValidEnum(String x) {
3936      return _enum.isEmpty() || _enum.contains(x);
3937   }
3938
3939   private boolean isValidMinLength(String x) {
3940      return minLength == null || x.length() >= minLength;
3941   }
3942
3943   private boolean isValidMaxLength(String x) {
3944      return maxLength == null || x.length() <= maxLength;
3945   }
3946
3947   private boolean isValidMinItems(Object x) {
3948      return minItems == null || Array.getLength(x) >= minItems;
3949   }
3950
3951   private boolean isValidMaxItems(Object x) {
3952      return maxItems == null || Array.getLength(x) <= maxItems;
3953   }
3954
3955   private boolean isValidUniqueItems(Object x) {
3956      if (uniqueItems) {
3957         Set<Object> s = new HashSet<>();
3958         for (int i = 0; i < Array.getLength(x); i++) {
3959            Object o = Array.get(x, i);
3960            if (! s.add(o))
3961               return false;
3962         }
3963      }
3964      return true;
3965   }
3966
3967   private boolean isValidMinItems(Collection<?> x) {
3968      return minItems == null || x.size() >= minItems;
3969   }
3970
3971   private boolean isValidMaxItems(Collection<?> x) {
3972      return maxItems == null || x.size() <= maxItems;
3973   }
3974
3975   private boolean isValidUniqueItems(Collection<?> x) {
3976      if (uniqueItems && ! (x instanceof Set)) {
3977         Set<Object> s = new HashSet<>();
3978         for (Object o : x)
3979            if (! s.add(o))
3980               return false;
3981      }
3982      return true;
3983   }
3984
3985   /**
3986    * Returns the schema information for the specified property.
3987    *
3988    * @param name The property name.
3989    * @return The schema information for the specified property, or <jk>null</jk> if properties are not defined on this schema.
3990    */
3991   public HttpPartSchema getProperty(String name) {
3992      if (properties != null) {
3993         HttpPartSchema schema = properties.get(name);
3994         if (schema != null)
3995            return schema;
3996      }
3997      return additionalProperties;
3998   }
3999
4000   /**
4001    * Returns <jk>true</jk> if this schema has properties associated with it.
4002    *
4003    * @return <jk>true</jk> if this schema has properties associated with it.
4004    */
4005   public boolean hasProperties() {
4006      return properties != null || additionalProperties != null;
4007   }
4008
4009   private static <T> Set<T> copy(Set<T> in) {
4010      return in == null ? emptySet() : unmodifiable(copyOf(in));
4011   }
4012
4013   private static Map<String,HttpPartSchema> build(Map<String,Object> in, boolean noValidate) {
4014      if (in == null)
4015         return null;
4016      Map<String,HttpPartSchema> m = map();
4017      in.forEach((k,v) -> m.put(k, build(v, noValidate)));
4018      return unmodifiable(m);
4019   }
4020
4021   private static HttpPartSchema build(Object in, boolean noValidate) {
4022      if (in == null)
4023         return null;
4024      if (in instanceof HttpPartSchema)
4025         return (HttpPartSchema)in;
4026      return ((Builder)in).noValidate(noValidate).build();
4027   }
4028
4029   //-----------------------------------------------------------------------------------------------------------------
4030   // Helper methods.
4031   //-----------------------------------------------------------------------------------------------------------------
4032
4033   private boolean resolve(Boolean b) {
4034      return b == null ? false : b;
4035   }
4036
4037   final static Set<String> toSet(String[]...s) {
4038      boolean isNotEmpty = false;
4039      for (String[] ss : s)
4040         isNotEmpty |= ss.length > 0;
4041      if (! isNotEmpty)
4042         return null;
4043      Set<String> set = set();
4044      for (String[] ss : s)
4045         if (ss != null)
4046            for (String ss2 : ss)
4047               split(ss2, x -> set.add(x));
4048      return set.isEmpty() ? null : set;
4049   }
4050
4051   final static Set<String> toSet(String s) {
4052      if (isEmpty(s))
4053         return null;
4054      Set<String> set = set();
4055      try {
4056         JsonList.ofJsonOrCdl(s).forEach(x -> set.add(x.toString()));
4057      } catch (ParseException e) {
4058         throw asRuntimeException(e);
4059      }
4060      return set;
4061   }
4062
4063   final static Number toNumber(String...s) {
4064      try {
4065         for (String ss : s)
4066            if (isNotEmpty(ss))
4067               return parseNumber(ss, Number.class);
4068         return null;
4069      } catch (ParseException e) {
4070         throw asRuntimeException(e);
4071      }
4072   }
4073
4074   final static JsonMap toJsonMap(String[] ss) {
4075      String s = joinnl(ss);
4076      if (s.isEmpty())
4077         return null;
4078      if (! isJsonObject(s, true))
4079         s = "{" + s + "}";
4080      try {
4081         return JsonMap.ofJson(s);
4082      } catch (ParseException e) {
4083         throw asRuntimeException(e);
4084      }
4085   }
4086
4087   @Override
4088   public String toString() {
4089      try {
4090         Predicate<Object> ne = x -> isNotEmpty(stringify(x));
4091         Predicate<Boolean> nf = ObjectUtils::isTrue;
4092         Predicate<Number> nm1 = ObjectUtils::isNotMinusOne;
4093         Predicate<Object> nn = ObjectUtils::isNotNull;
4094         JsonMap m = new JsonMap()
4095            .appendIf(ne, "name", name)
4096            .appendIf(ne, "type", type)
4097            .appendIf(ne, "format", format)
4098            .appendIf(ne, "default", _default)
4099            .appendIf(ne, "enum", _enum)
4100            .appendIf(ne, "properties", properties)
4101            .appendIf(nf, "allowEmptyValue", allowEmptyValue)
4102            .appendIf(nf, "exclusiveMaximum", exclusiveMaximum)
4103            .appendIf(nf, "exclusiveMinimum", exclusiveMinimum)
4104            .appendIf(nf, "required", required)
4105            .appendIf(nf, "uniqueItems", uniqueItems)
4106            .appendIf(nf, "skipIfEmpty", skipIfEmpty)
4107            .appendIf(x -> x != HttpPartCollectionFormat.NO_COLLECTION_FORMAT, "collectionFormat", collectionFormat)
4108            .appendIf(ne, "pattern", pattern)
4109            .appendIf(nn, "items", items)
4110            .appendIf(nn, "additionalProperties", additionalProperties)
4111            .appendIf(nm1, "maximum", maximum)
4112            .appendIf(nm1, "minimum", minimum)
4113            .appendIf(nm1, "multipleOf", multipleOf)
4114            .appendIf(nm1, "maxLength", maxLength)
4115            .appendIf(nm1, "minLength", minLength)
4116            .appendIf(nm1, "maxItems", maxItems)
4117            .appendIf(nm1, "minItems", minItems)
4118            .appendIf(nm1, "maxProperties", maxProperties)
4119            .appendIf(nm1, "minProperties", minProperties)
4120            .append("parsedType", parsedType)
4121         ;
4122         return m.toString();
4123      } catch (Exception e) {
4124         return "";
4125      }
4126   }
4127}