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 org.apache.juneau.internal.StringUtils.*;
016
017import java.lang.annotation.*;
018import java.lang.reflect.*;
019import java.util.*;
020import java.util.regex.*;
021
022import org.apache.juneau.*;
023import org.apache.juneau.http.annotation.*;
024import org.apache.juneau.jsonschema.annotation.Schema;
025import org.apache.juneau.jsonschema.annotation.Items;
026import org.apache.juneau.jsonschema.annotation.SubItems;
027import org.apache.juneau.httppart.HttpPartSchema.*;
028import org.apache.juneau.httppart.HttpPartSchema.Type;
029import org.apache.juneau.internal.*;
030import org.apache.juneau.utils.*;
031
032/**
033 * The builder class for creating {@link HttpPartSchema} objects.
034 *
035 */
036public class HttpPartSchemaBuilder {
037   String name, _default;
038   Set<Integer> codes;
039   Set<String> _enum;
040   Boolean allowEmptyValue, exclusiveMaximum, exclusiveMinimum, required, uniqueItems, skipIfEmpty;
041   CollectionFormat collectionFormat = CollectionFormat.NO_COLLECTION_FORMAT;
042   Type type = Type.NO_TYPE;
043   Format format = Format.NO_FORMAT;
044   Pattern pattern;
045   Number maximum, minimum, multipleOf;
046   Long maxLength, minLength, maxItems, minItems, maxProperties, minProperties;
047   Map<String,HttpPartSchemaBuilder> properties;
048   HttpPartSchemaBuilder items, additionalProperties;
049   boolean noValidate;
050   Class<? extends HttpPartParser> parser;
051   Class<? extends HttpPartSerializer> serializer;
052
053   /**
054    * Instantiates a new {@link HttpPartSchema} object based on the configuration of this builder.
055    *
056    * <p>
057    * This method can be called multiple times to produce new schema objects.
058    *
059    * @return
060    *    A new {@link HttpPartSchema} object.
061    *    <br>Never <jk>null</jk>.
062    */
063   public HttpPartSchema build() {
064      return new HttpPartSchema(this);
065   }
066
067   HttpPartSchemaBuilder apply(Class<? extends Annotation> c, Method m, int index) {
068      apply(c, m.getGenericParameterTypes()[index]);
069      for (Annotation a :  m.getParameterAnnotations()[index])
070         if (c.isInstance(a))
071            apply(a);
072      return this;
073   }
074
075   HttpPartSchemaBuilder apply(Class<? extends Annotation> c, Method m) {
076      apply(c, m.getGenericReturnType());
077      Annotation a = m.getAnnotation(c);
078      if (a != null)
079         return apply(a);
080      return this;
081   }
082
083   HttpPartSchemaBuilder apply(Class<? extends Annotation> c, java.lang.reflect.Type t) {
084      if (t instanceof Class<?>) {
085         Class<?> tc = (Class<?>)t;
086         for (Annotation a : ClassUtils.getAnnotationsParentFirst(c, tc))
087            apply(a);
088      } else if (Value.isType(t)) {
089         apply(c, Value.getParameterType(t));
090      }
091      return this;
092   }
093
094   /**
095    * Apply the specified annotation to this schema.
096    *
097    * @param a The annotation to apply.
098    * @return This object (for method chaining).
099    */
100   @SuppressWarnings("deprecation")
101   public HttpPartSchemaBuilder apply(Annotation a) {
102      if (a instanceof Body)
103         apply((Body)a);
104      else if (a instanceof Header)
105         apply((Header)a);
106      else if (a instanceof FormData)
107         apply((FormData)a);
108      else if (a instanceof Query)
109         apply((Query)a);
110      else if (a instanceof Path)
111         apply((Path)a);
112      else if (a instanceof org.apache.juneau.remoteable.Body)
113         apply((org.apache.juneau.remoteable.Body)a);
114      else if (a instanceof org.apache.juneau.remoteable.Header)
115         apply((org.apache.juneau.remoteable.Header)a);
116      else if (a instanceof org.apache.juneau.remoteable.FormData)
117         apply((org.apache.juneau.remoteable.FormData)a);
118      else if (a instanceof org.apache.juneau.remoteable.Query)
119         apply((org.apache.juneau.remoteable.Query)a);
120      else if (a instanceof org.apache.juneau.remoteable.Path)
121         apply((org.apache.juneau.remoteable.Path)a);
122      else if (a instanceof Response)
123         apply((Response)a);
124      else if (a instanceof ResponseHeader)
125         apply((ResponseHeader)a);
126      else if (a instanceof HasQuery)
127         apply((HasQuery)a);
128      else if (a instanceof HasFormData)
129         apply((HasFormData)a);
130      else if (a instanceof Schema)
131         apply((Schema)a);
132      else
133         throw new RuntimeException("HttpPartSchemaBuilder.apply(@"+a.getClass().getSimpleName()+") not defined");
134      return this;
135   }
136
137   HttpPartSchemaBuilder apply(Body a) {
138      required(a.required());
139      allowEmptyValue(! a.required());
140      apply(a.schema());
141      return this;
142   }
143
144   @SuppressWarnings("deprecation")
145   HttpPartSchemaBuilder apply(org.apache.juneau.remoteable.Body a) {
146      return this;
147   }
148
149   HttpPartSchemaBuilder apply(Header a) {
150      name(a.value());
151      name(a.name());
152      required(a.required());
153      type(a.type());
154      format(a.format());
155      allowEmptyValue(a.allowEmptyValue());
156      items(a.items());
157      collectionFormat(a.collectionFormat());
158      _default(a._default().length == 0 ? null : joinnl(a._default()));
159      maximum(HttpPartSchema.toNumber(a.maximum()));
160      exclusiveMaximum(a.exclusiveMaximum());
161      minimum(HttpPartSchema.toNumber(a.minimum()));
162      exclusiveMinimum(a.exclusiveMinimum());
163      maxLength(a.maxLength());
164      minLength(a.minLength());
165      pattern(a.pattern());
166      maxItems(a.maxItems());
167      minItems(a.minItems());
168      uniqueItems(a.uniqueItems());
169      _enum(HttpPartSchema.toSet(a._enum()));
170      multipleOf(HttpPartSchema.toNumber(a.multipleOf()));
171      skipIfEmpty(a.skipIfEmpty());
172      parser(a.parser());
173      serializer(a.serializer());
174      return this;
175   }
176
177   @SuppressWarnings("deprecation")
178   HttpPartSchemaBuilder apply(org.apache.juneau.remoteable.Header a) {
179      name(a.value());
180      name(a.name());
181      skipIfEmpty(a.skipIfEmpty());
182      serializer(a.serializer());
183      return this;
184   }
185
186   HttpPartSchemaBuilder apply(ResponseHeader a) {
187      name(a.value());
188      name(a.name());
189      codes(a.code());
190      type(a.type());
191      format(a.format());
192      items(a.items());
193      collectionFormat(a.collectionFormat());
194      _default(a._default().length == 0 ? null : joinnl(a._default()));
195      maximum(HttpPartSchema.toNumber(a.maximum()));
196      exclusiveMaximum(a.exclusiveMaximum());
197      minimum(HttpPartSchema.toNumber(a.minimum()));
198      exclusiveMinimum(a.exclusiveMinimum());
199      maxLength(a.maxLength());
200      minLength(a.minLength());
201      pattern(a.pattern());
202      maxItems(a.maxItems());
203      minItems(a.minItems());
204      uniqueItems(a.uniqueItems());
205      _enum(HttpPartSchema.toSet(a._enum()));
206      multipleOf(HttpPartSchema.toNumber(a.multipleOf()));
207      allowEmptyValue(false);
208      serializer(a.serializer());
209      return this;
210   }
211
212   HttpPartSchemaBuilder apply(FormData a) {
213      name(a.value());
214      name(a.name());
215      required(a.required());
216      type(a.type());
217      format(a.format());
218      allowEmptyValue(a.allowEmptyValue());
219      items(a.items());
220      collectionFormat(a.collectionFormat());
221      _default(a._default().length == 0 ? null : joinnl(a._default()));
222      maximum(HttpPartSchema.toNumber(a.maximum()));
223      exclusiveMaximum(a.exclusiveMaximum());
224      minimum(HttpPartSchema.toNumber(a.minimum()));
225      exclusiveMinimum(a.exclusiveMinimum());
226      maxLength(a.maxLength());
227      minLength(a.minLength());
228      pattern(a.pattern());
229      maxItems(a.maxItems());
230      minItems(a.minItems());
231      uniqueItems(a.uniqueItems());
232      _enum(HttpPartSchema.toSet(a._enum()));
233      multipleOf(HttpPartSchema.toNumber(a.multipleOf()));
234      skipIfEmpty(a.skipIfEmpty());
235      parser(a.parser());
236      serializer(a.serializer());
237      return this;
238   }
239
240   @SuppressWarnings("deprecation")
241   HttpPartSchemaBuilder apply(org.apache.juneau.remoteable.FormData a) {
242      name(a.value());
243      name(a.name());
244      skipIfEmpty(a.skipIfEmpty());
245      serializer(a.serializer());
246      return this;
247   }
248
249   HttpPartSchemaBuilder apply(Query a) {
250      name(a.value());
251      name(a.name());
252      required(a.required());
253      type(a.type());
254      format(a.format());
255      allowEmptyValue(a.allowEmptyValue());
256      items(a.items());
257      collectionFormat(a.collectionFormat());
258      _default(a._default().length == 0 ? null : joinnl(a._default()));
259      maximum(HttpPartSchema.toNumber(a.maximum()));
260      exclusiveMaximum(a.exclusiveMaximum());
261      minimum(HttpPartSchema.toNumber(a.minimum()));
262      exclusiveMinimum(a.exclusiveMinimum());
263      maxLength(a.maxLength());
264      minLength(a.minLength());
265      pattern(a.pattern());
266      maxItems(a.maxItems());
267      minItems(a.minItems());
268      uniqueItems(a.uniqueItems());
269      _enum(HttpPartSchema.toSet(a._enum()));
270      multipleOf(HttpPartSchema.toNumber(a.multipleOf()));
271      skipIfEmpty(a.skipIfEmpty());
272      parser(a.parser());
273      serializer(a.serializer());
274      return this;
275   }
276
277   @SuppressWarnings("deprecation")
278   HttpPartSchemaBuilder apply(org.apache.juneau.remoteable.Query a) {
279      name(a.value());
280      name(a.name());
281      skipIfEmpty(a.skipIfEmpty());
282      serializer(a.serializer());
283      return this;
284   }
285
286   HttpPartSchemaBuilder apply(Path a) {
287      name(a.value());
288      name(a.name());
289      type(a.type());
290      format(a.format());
291      items(a.items());
292      allowEmptyValue(a.allowEmptyValue());
293      collectionFormat(a.collectionFormat());
294      maximum(HttpPartSchema.toNumber(a.maximum()));
295      exclusiveMaximum(a.exclusiveMaximum());
296      minimum(HttpPartSchema.toNumber(a.minimum()));
297      exclusiveMinimum(a.exclusiveMinimum());
298      maxLength(a.maxLength());
299      minLength(a.minLength());
300      pattern(a.pattern());
301      maxItems(a.maxItems());
302      minItems(a.minItems());
303      uniqueItems(a.uniqueItems());
304      _enum(HttpPartSchema.toSet(a._enum()));
305      multipleOf(HttpPartSchema.toNumber(a.multipleOf()));
306      parser(a.parser());
307      serializer(a.serializer());
308
309      // Path remainder always allows empty value.
310      if (startsWith(name, '/'))
311         allowEmptyValue();
312      else
313         required(true);
314
315      return this;
316   }
317
318   @SuppressWarnings("deprecation")
319   HttpPartSchemaBuilder apply(org.apache.juneau.remoteable.Path a) {
320      name(a.value());
321      name(a.name());
322      serializer(a.serializer());
323
324      // Path remainder always allows empty value.
325      if (startsWith(name, '/'))
326         allowEmptyValue();
327      else
328         required(true);
329
330      return this;
331   }
332
333   HttpPartSchemaBuilder apply(Response a) {
334      codes(a.value());
335      codes(a.code());
336      required(false);
337      allowEmptyValue(true);
338      serializer(a.partSerializer());
339      parser(a.partParser());
340      apply(a.schema());
341      return this;
342   }
343
344   HttpPartSchemaBuilder apply(Items a) {
345      type(a.type());
346      format(a.format());
347      items(a.items());
348      collectionFormat(a.collectionFormat());
349      _default(a._default().length == 0 ? null : joinnl(a._default()));
350      maximum(HttpPartSchema.toNumber(a.maximum()));
351      exclusiveMaximum(a.exclusiveMaximum());
352      minimum(HttpPartSchema.toNumber(a.minimum()));
353      exclusiveMinimum(a.exclusiveMinimum());
354      maxLength(a.maxLength());
355      minLength(a.minLength());
356      pattern(a.pattern());
357      maxItems(a.maxItems());
358      minItems(a.minItems());
359      uniqueItems(a.uniqueItems());
360      _enum(HttpPartSchema.toSet(a._enum()));
361      multipleOf(HttpPartSchema.toNumber(a.multipleOf()));
362      return this;
363   }
364
365   HttpPartSchemaBuilder apply(SubItems a) {
366      type(a.type());
367      format(a.format());
368      items(HttpPartSchema.toObjectMap(a.items()));
369      collectionFormat(a.collectionFormat());
370      _default(a._default().length == 0 ? null : joinnl(a._default()));
371      maximum(HttpPartSchema.toNumber(a.maximum()));
372      exclusiveMaximum(a.exclusiveMaximum());
373      minimum(HttpPartSchema.toNumber(a.minimum()));
374      exclusiveMinimum(a.exclusiveMinimum());
375      maxLength(a.maxLength());
376      minLength(a.minLength());
377      pattern(a.pattern());
378      maxItems(a.maxItems());
379      minItems(a.minItems());
380      uniqueItems(a.uniqueItems());
381      _enum(HttpPartSchema.toSet(a._enum()));
382      multipleOf(HttpPartSchema.toNumber(a.multipleOf()));
383      return this;
384   }
385
386   HttpPartSchemaBuilder apply(Schema a) {
387      type(a.type());
388      format(a.format());
389      items(a.items());
390      collectionFormat(a.collectionFormat());
391      _default(a._default().length == 0 ? null : joinnl(a._default()));
392      maximum(HttpPartSchema.toNumber(a.maximum()));
393      exclusiveMaximum(a.exclusiveMaximum());
394      minimum(HttpPartSchema.toNumber(a.minimum()));
395      exclusiveMinimum(a.exclusiveMinimum());
396      maxLength(a.maxLength());
397      minLength(a.minLength());
398      pattern(a.pattern());
399      maxItems(a.maxItems());
400      minItems(a.minItems());
401      uniqueItems(a.uniqueItems());
402      _enum(HttpPartSchema.toSet(a._enum()));
403      multipleOf(HttpPartSchema.toNumber(a.multipleOf()));
404      maxProperties(a.maxProperties());
405      minProperties(a.minProperties());
406      properties(HttpPartSchema.toObjectMap(a.properties()));
407      additionalProperties(HttpPartSchema.toObjectMap(a.additionalProperties()));
408      return this;
409   }
410
411   HttpPartSchemaBuilder apply(HasQuery a) {
412      name(a.value());
413      name(a.name());
414      return this;
415   }
416
417   HttpPartSchemaBuilder apply(HasFormData a) {
418      name(a.value());
419      name(a.name());
420      return this;
421   }
422
423   HttpPartSchemaBuilder apply(ObjectMap m) {
424      if (m != null && ! m.isEmpty()) {
425         _default(m.getString("default"));
426         _enum(HttpPartSchema.toSet(m.getString("enum")));
427         allowEmptyValue(m.getBoolean("allowEmptyValue"));
428         exclusiveMaximum(m.getBoolean("exclusiveMaximum"));
429         exclusiveMinimum(m.getBoolean("exclusiveMinimum"));
430         required(m.getBoolean("required"));
431         uniqueItems(m.getBoolean("uniqueItems"));
432         collectionFormat(m.getString("collectionFormat"));
433         type(m.getString("type"));
434         format(m.getString("format"));
435         pattern(m.getString("pattern"));
436         maximum(m.get("maximum", Number.class));
437         minimum(m.get("minimum", Number.class));
438         multipleOf(m.get("multipleOf", Number.class));
439         maxItems(m.get("maxItems", Long.class));
440         maxLength(m.get("maxLength", Long.class));
441         maxProperties(m.get("maxProperties", Long.class));
442         minItems(m.get("minItems", Long.class));
443         minLength(m.get("minLength", Long.class));
444         minProperties(m.get("minProperties", Long.class));
445
446         items(m.getObjectMap("items"));
447         properties(m.getObjectMap("properties"));
448         additionalProperties(m.getObjectMap("additionalProperties"));
449
450         apply(m.getObjectMap("schema", null));
451      }
452      return this;
453   }
454
455   /**
456    * <mk>name</mk> field.
457    *
458    * <p>
459    * Applicable to the following Swagger schema objects:
460    * <ul>
461    *    <li>{@doc SwaggerParameterObject Parameter}
462    *    <li>{@doc SwaggerHeaderObject Header}
463    * </ul>
464    *
465    * @param value
466    *    The new value for this property.
467    * @return This object (for method chaining).
468    */
469   public HttpPartSchemaBuilder name(String value) {
470      if (isNotEmpty(value))
471         name = value;
472      return this;
473   }
474
475   /**
476    * <mk>httpStatusCode</mk> key.
477    *
478    * <p>
479    * Applicable to the following Swagger schema objects:
480    * <ul>
481    *    <li>{@doc SwaggerResponsesObject Responses}
482    * </ul>
483    *
484    * @param value
485    *    The new value for this property.
486    *    <br>Ignored if <jk>null</jk> or an empty array.
487    * @return This object (for method chaining).
488    */
489   public HttpPartSchemaBuilder codes(int[] value) {
490      if (value != null && value.length != 0)
491         for (int v : value)
492            code(v);
493      return this;
494   }
495
496   /**
497    * <mk>httpStatusCode</mk> key.
498    *
499    * <p>
500    * Applicable to the following Swagger schema objects:
501    * <ul>
502    *    <li>{@doc SwaggerResponsesObject Responses}
503    * </ul>
504    *
505    * @param value
506    *    The new value for this property.
507    *    <br>Ignored if value is <code>0</code>.
508    * @return This object (for method chaining).
509    */
510   public HttpPartSchemaBuilder code(int value) {
511      if (value != 0) {
512         if (codes == null)
513            codes = new TreeSet<>();
514         codes.add(value);
515      }
516      return this;
517   }
518
519   /**
520    * <mk>required</mk> field.
521    *
522    * <p>
523    * Determines whether the parameter is mandatory.
524    *
525    * <p>
526    * Applicable to the following Swagger schema objects:
527    * <ul>
528    *    <li>{@doc SwaggerParameterObject Parameter}
529    *    <li>{@doc SwaggerSchemaObject Schema}
530    * </ul>
531    *
532    * @param value
533    *    The new value for this property.
534    *    <br>Ignored if value is <jk>null</jk>.
535    * @return This object (for method chaining).
536    */
537   public HttpPartSchemaBuilder required(Boolean value) {
538      required = resolve(value, required);
539      return this;
540   }
541
542   /**
543    * <mk>required</mk> field.
544    *
545    * <p>
546    * Determines whether the parameter is mandatory.
547    *
548    * <p>
549    * Same as {@link #required(Boolean)} but takes in a boolean value as a string.
550    *
551    * @param value
552    *    The new value for this property.
553    *    <br>Ignored if value is <jk>null</jk> or empty.
554    * @return This object (for method chaining).
555    */
556   public HttpPartSchemaBuilder required(String value) {
557      required = resolve(value, required);
558      return this;
559   }
560
561   /**
562    * <mk>required</mk> field.
563    *
564    * <p>
565    * Shortcut for calling <code>required(<jk>true</jk>);</code>.
566    *
567    * @return This object (for method chaining).
568    */
569   public HttpPartSchemaBuilder required() {
570      return required(true);
571   }
572
573   /**
574    * <mk>type</mk> field.
575    *
576    * <p>
577    * The type of the parameter.
578    *
579    * <p>
580    * The possible values are:
581    * <ul class='spaced-list'>
582    *    <li>
583    *       <js>"string"</js>
584    *       <br>Parameter must be a string or a POJO convertible from a string.
585    *    <li>
586    *       <js>"number"</js>
587    *       <br>Parameter must be a number primitive or number object.
588    *       <br>If parameter is <code>Object</code>, creates either a <code>Float</code> or <code>Double</code> depending on the size of the number.
589    *    <li>
590    *       <js>"integer"</js>
591    *       <br>Parameter must be a integer/long primitive or integer/long object.
592    *       <br>If parameter is <code>Object</code>, creates either a <code>Short</code>, <code>Integer</code>, or <code>Long</code> depending on the size of the number.
593    *    <li>
594    *       <js>"boolean"</js>
595    *       <br>Parameter must be a boolean primitive or object.
596    *    <li>
597    *       <js>"array"</js>
598    *       <br>Parameter must be an array or collection.
599    *       <br>Elements must be strings or POJOs convertible from strings.
600    *       <br>If parameter is <code>Object</code>, creates an {@link ObjectList}.
601    *    <li>
602    *       <js>"object"</js>
603    *       <br>Parameter must be a map or bean.
604    *       <br>If parameter is <code>Object</code>, creates an {@link ObjectMap}.
605    *       <br>Note that this is an extension of the OpenAPI schema as Juneau allows for arbitrarily-complex POJOs to be serialized as HTTP parts.
606    *    <li>
607    *       <js>"file"</js>
608    *       <br>This type is currently not supported.
609    * </ul>
610    *
611    * <p>
612    * If the type is not specified, it will be auto-detected based on the parameter class type.
613    *
614    * <p>
615    * Applicable to the following Swagger schema objects:
616    * <ul>
617    *    <li>{@doc SwaggerParameterObject Parameter}
618    *    <li>{@doc SwaggerSchemaObject Schema}
619    *    <li>{@doc SwaggerItemsObject Items}
620    *    <li>{@doc SwaggerSecuritySchemeObject SecurityScheme}
621    * </ul>
622    *
623    * <h5 class='section'>See Also:</h5>
624    * <ul class='doctree'>
625    *    <li class='extlink'>{@doc SwaggerDataTypes}
626    * </ul>
627    *
628    * @param value
629    *    The new value for this property.
630    *    <br>Ignored if value is <jk>null</jk> or empty.
631    * @return This object (for method chaining).
632    */
633   public HttpPartSchemaBuilder type(String value) {
634      try {
635         if (isNotEmpty(value))
636            type = Type.fromString(value);
637      } catch (Exception e) {
638         throw new ContextRuntimeException("Invalid value ''{0}'' passed in as type value.  Valid values: {1}", value, Type.values());
639      }
640      return this;
641   }
642
643   /**
644    * <mk>format</mk> field.
645    *
646    * <p>
647    * The extending format for the previously mentioned {@doc SwaggerParameterTypes parameter type}.
648    *
649    * <p>
650    * The possible values are:
651    * <ul class='spaced-list'>
652    *    <li>
653    *       <js>"int32"</js> - Signed 32 bits.
654    *       <br>Only valid with type <js>"integer"</js>.
655    *    <li>
656    *       <js>"int64"</js> - Signed 64 bits.
657    *       <br>Only valid with type <js>"integer"</js>.
658    *    <li>
659    *       <js>"float"</js> - 32-bit floating point number.
660    *       <br>Only valid with type <js>"number"</js>.
661    *    <li>
662    *       <js>"double"</js> - 64-bit floating point number.
663    *       <br>Only valid with type <js>"number"</js>.
664    *    <li>
665    *       <js>"byte"</js> - BASE-64 encoded characters.
666    *       <br>Only valid with type <js>"string"</js>.
667    *       <br>Parameters of type POJO convertible from string are converted after the string has been decoded.
668    *    <li>
669    *       <js>"binary"</js> - Hexadecimal encoded octets (e.g. <js>"00FF"</js>).
670    *       <br>Only valid with type <js>"string"</js>.
671    *       <br>Parameters of type POJO convertible from string are converted after the string has been decoded.
672    *    <li>
673    *       <js>"binary-spaced"</js> - Hexadecimal encoded octets, spaced (e.g. <js>"00 FF"</js>).
674    *       <br>Only valid with type <js>"string"</js>.
675    *       <br>Parameters of type POJO convertible from string are converted after the string has been decoded.
676    *    <li>
677    *       <js>"date"</js> - An <a href='http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14'>RFC3339 full-date</a>.
678    *       <br>Only valid with type <js>"string"</js>.
679    *    <li>
680    *       <js>"date-time"</js> - An <a href='http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14'>RFC3339 date-time</a>.
681    *       <br>Only valid with type <js>"string"</js>.
682    *    <li>
683    *       <js>"password"</js> - Used to hint UIs the input needs to be obscured.
684    *       <br>This format does not affect the serialization or parsing of the parameter.
685    *    <li>
686    *       <js>"uon"</js> - UON notation (e.g. <js>"(foo=bar,baz=@(qux,123))"</js>).
687    *       <br>Only valid with type <js>"object"</js>.
688    *       <br>If not specified, then the input is interpreted as plain-text and is converted to a POJO directly.
689    * </ul>
690    *
691    * <p>
692    * Applicable to the following Swagger schema objects:
693    * <ul>
694    *    <li>{@doc SwaggerParameterObject Parameter}
695    *    <li>{@doc SwaggerSchemaObject Schema}
696    *    <li>{@doc SwaggerItemsObject Items}
697    *    <li>{@doc SwaggerHeaderObject Header}
698    * </ul>
699    *
700    * <h5 class='section'>See Also:</h5>
701    * <ul class='doctree'>
702    *    <li class='extlink'>{@doc SwaggerDataTypeFormats}
703    * </ul>
704    *
705    * @param value
706    *    The new value for this property.
707    *    <br>Ignored if value is <jk>null</jk> or empty.
708    * @return This object (for method chaining).
709    */
710   public HttpPartSchemaBuilder format(String value) {
711      try {
712         if (isNotEmpty(value))
713            format = Format.fromString(value);
714      } catch (Exception e) {
715         throw new ContextRuntimeException("Invalid value ''{0}'' passed in as format value.  Valid values: {1}", value, Format.values());
716      }
717      return this;
718   }
719
720   /**
721    * <mk>allowEmptyValue</mk> field.
722    *
723    * <p>
724    * Sets the ability to pass empty-valued parameters.
725    * <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.
726    * <br>The default value is <jk>false</jk>.
727    *
728    * <p>
729    * Applicable to the following Swagger schema objects:
730    * <ul>
731    *    <li>{@doc SwaggerParameterObject Parameter}
732    * </ul>
733    *
734    * @param value
735    *    The new value for this property.
736    *    <br>Ignored if value is <jk>null</jk>.
737    * @return This object (for method chaining).
738    */
739   public HttpPartSchemaBuilder allowEmptyValue(Boolean value) {
740      allowEmptyValue = resolve(value, allowEmptyValue);
741      return this;
742   }
743
744   /**
745    * <mk>allowEmptyValue</mk> field.
746    *
747    * <p>
748    * Same as {@link #allowEmptyValue(Boolean)} but takes in a string boolean value.
749    *
750    * @param value
751    *    The new value for this property.
752    *    <br>Ignored if value is <jk>null</jk> or empty.
753    * @return This object (for method chaining).
754    */
755   public HttpPartSchemaBuilder allowEmptyValue(String value) {
756      allowEmptyValue = resolve(value, allowEmptyValue);
757      return this;
758   }
759
760   /**
761    * <mk>allowEmptyValue</mk> field.
762    *
763    * <p>
764    * Shortcut for calling <code>allowEmptyValue(<jk>true</jk>);</code>.
765    *
766    * @return This object (for method chaining).
767    */
768   public HttpPartSchemaBuilder allowEmptyValue() {
769      return allowEmptyValue(true);
770   }
771
772   /**
773    * <mk>items</mk> field.
774    *
775    * <p>
776    * Describes the type of items in the array.
777    * <p>
778    * Required if <code>type</code> is <js>"array"</js>.
779    * <br>Can only be used if <code>type</code> is <js>"array"</js>.
780    *
781    * <p>
782    * Applicable to the following Swagger schema objects:
783    * <ul>
784    *    <li>{@doc SwaggerParameterObject Parameter}
785    *    <li>{@doc SwaggerSchemaObject Schema}
786    *    <li>{@doc SwaggerItemsObject Items}
787    *    <li>{@doc SwaggerHeaderObject Header}
788    * </ul>
789    *
790    * @param value
791    *    The new value for this property.
792    *    <br>Ignored if value is <jk>null</jk> or empty.
793    * @return This object (for method chaining).
794    */
795   public HttpPartSchemaBuilder items(HttpPartSchemaBuilder value) {
796      if (value != null)
797         this.items = value;
798      return this;
799   }
800
801   HttpPartSchemaBuilder items(ObjectMap value) {
802      if (value != null && ! value.isEmpty())
803         items = HttpPartSchema.create().apply(value);
804      return this;
805   }
806
807   HttpPartSchemaBuilder items(Items value) {
808      if (! AnnotationUtils.empty(value))
809         items = HttpPartSchema.create().apply(value);
810      return this;
811   }
812
813   HttpPartSchemaBuilder items(SubItems value) {
814      if (! AnnotationUtils.empty(value))
815         items = HttpPartSchema.create().apply(value);
816      return this;
817   }
818
819
820   /**
821    * <mk>collectionFormat</mk> field.
822    *
823    * <p>
824    * Determines the format of the array if <code>type</code> <js>"array"</js> is used.
825    * <br>Can only be used if <code>type</code> is <js>"array"</js>.
826    *
827    * <br>Possible values are:
828    * <ul class='spaced-list'>
829    *    <li>
830    *       <js>"csv"</js> (default) - Comma-separated values (e.g. <js>"foo,bar"</js>).
831    *    <li>
832    *       <js>"ssv"</js> - Space-separated values (e.g. <js>"foo bar"</js>).
833    *    <li>
834    *       <js>"tsv"</js> - Tab-separated values (e.g. <js>"foo\tbar"</js>).
835    *    <li>
836    *       <js>"pipes</js> - Pipe-separated values (e.g. <js>"foo|bar"</js>).
837    *    <li>
838    *       <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>).
839    *    <li>
840    *       <js>"uon"</js> - UON notation (e.g. <js>"@(foo,bar)"</js>).
841    *    <li>
842    * </ul>
843    *
844    * <p>
845    * Applicable to the following Swagger schema objects:
846    * <ul>
847    *    <li>{@doc SwaggerParameterObject Parameter}
848    *    <li>{@doc SwaggerItemsObject Items}
849    *    <li>{@doc SwaggerHeaderObject Header}
850    * </ul>
851    *
852    * <p>
853    * Note that for collections/arrays parameters with POJO element types, the input is broken into a string array before being converted into POJO elements.
854    *
855    * @param value
856    *    The new value for this property.
857    *    <br>Ignored if value is <jk>null</jk> or empty.
858    * @return This object (for method chaining).
859    */
860   public HttpPartSchemaBuilder collectionFormat(String value) {
861      try {
862         if (isNotEmpty(value))
863            this.collectionFormat = CollectionFormat.fromString(value);
864      } catch (Exception e) {
865         throw new ContextRuntimeException("Invalid value ''{0}'' passed in as collectionFormat value.  Valid values: {1}", value, CollectionFormat.values());
866      }
867      return this;
868   }
869
870   /**
871    * <mk>default</mk> field.
872    *
873    * <p>
874    * 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.
875    * <br>(Note: "default" has no meaning for required parameters.)
876    *
877    * <p>
878    * Applicable to the following Swagger schema objects:
879    * <ul>
880    *    <li>{@doc SwaggerParameterObject Parameter}
881    *    <li>{@doc SwaggerSchemaObject Schema}
882    *    <li>{@doc SwaggerItemsObject Items}
883    *    <li>{@doc SwaggerHeaderObject Header}
884    * </ul>
885    *
886    * @param value
887    *    The new value for this property.
888    *    <br>Ignored if value is <jk>null</jk>.
889    * @return This object (for method chaining).
890    */
891   public HttpPartSchemaBuilder _default(String value) {
892      if (value != null)
893         this._default = value;
894      return this;
895   }
896
897   /**
898    * <mk>maximum</mk> field.
899    *
900    * <p>
901    * Defines the maximum value for a parameter of numeric types.
902    *
903    * <p>
904    * Only allowed for the following types: <js>"integer"</js>, <js>"number"</js>.
905    *
906    * <p>
907    * Applicable to the following Swagger schema objects:
908    * <ul>
909    *    <li>{@doc SwaggerParameterObject Parameter}
910    *    <li>{@doc SwaggerSchemaObject Schema}
911    *    <li>{@doc SwaggerItemsObject Items}
912    *    <li>{@doc SwaggerHeaderObject Header}
913    * </ul>
914    *
915    * @param value
916    *    The new value for this property.
917    *    <br>Ignored if value is <jk>null</jk>.
918    * @return This object (for method chaining).
919    */
920   public HttpPartSchemaBuilder maximum(Number value) {
921      if (value != null)
922         this.maximum = value;
923      return this;
924   }
925
926   /**
927    * <mk>exclusiveMaximum</mk> field.
928    *
929    * <p>
930    * Defines whether the maximum is matched exclusively.
931    *
932    * <p>
933    * Only allowed for the following types: <js>"integer"</js>, <js>"number"</js>.
934    * <br>If <jk>true</jk>, must be accompanied with <code>maximum</code>.
935    *
936    * <p>
937    * Applicable to the following Swagger schema objects:
938    * <ul>
939    *    <li>{@doc SwaggerParameterObject Parameter}
940    *    <li>{@doc SwaggerSchemaObject Schema}
941    *    <li>{@doc SwaggerItemsObject Items}
942    *    <li>{@doc SwaggerHeaderObject Header}
943    * </ul>
944    *
945    * @param value
946    *    The new value for this property.
947    *    <br>Ignored if value is <jk>null</jk>.
948    * @return This object (for method chaining).
949    */
950   public HttpPartSchemaBuilder exclusiveMaximum(Boolean value) {
951      exclusiveMaximum = resolve(value, exclusiveMaximum);
952      return this;
953   }
954
955   /**
956    * <mk>exclusiveMaximum</mk> field.
957    *
958    * <p>
959    * Same as {@link #exclusiveMaximum(Boolean)} but takes in a string boolean value.
960    *
961    * @param value
962    *    The new value for this property.
963    *    <br>Ignored if value is <jk>null</jk> or empty.
964    * @return This object (for method chaining).
965    */
966   public HttpPartSchemaBuilder exclusiveMaximum(String value) {
967      exclusiveMaximum = resolve(value, exclusiveMaximum);
968      return this;
969   }
970
971   /**
972    * <mk>exclusiveMaximum</mk> field.
973    *
974    * <p>
975    * Shortcut for calling <code>exclusiveMaximum(<jk>true</jk>);</code>.
976    *
977    * @return This object (for method chaining).
978    */
979   public HttpPartSchemaBuilder exclusiveMaximum() {
980      return exclusiveMaximum(true);
981   }
982
983   /**
984    * <mk>minimum</mk> field.
985    *
986    * <p>
987    * Defines the minimum value for a parameter of numeric types.
988    *
989    * <p>
990    * Only allowed for the following types: <js>"integer"</js>, <js>"number"</js>.
991    *
992    * <p>
993    * Applicable to the following Swagger schema objects:
994    * <ul>
995    *    <li>{@doc SwaggerParameterObject Parameter}
996    *    <li>{@doc SwaggerSchemaObject Schema}
997    *    <li>{@doc SwaggerItemsObject Items}
998    *    <li>{@doc SwaggerHeaderObject Header}
999    * </ul>
1000    *
1001    * @param value
1002    *    The new value for this property.
1003    *    <br>Ignored if value is <jk>null</jk>.
1004    * @return This object (for method chaining).
1005    */
1006   public HttpPartSchemaBuilder minimum(Number value) {
1007      if (value != null)
1008         this.minimum = value;
1009      return this;
1010   }
1011
1012   /**
1013    * <mk>exclusiveMinimum</mk> field.
1014    *
1015    * <p>
1016    * Defines whether the minimum is matched exclusively.
1017    *
1018    * <p>
1019    * Only allowed for the following types: <js>"integer"</js>, <js>"number"</js>.
1020    * <br>If <jk>true</jk>, must be accompanied with <code>minimum</code>.
1021    *
1022    * <p>
1023    * Applicable to the following Swagger schema objects:
1024    * <ul>
1025    *    <li>{@doc SwaggerParameterObject Parameter}
1026    *    <li>{@doc SwaggerSchemaObject Schema}
1027    *    <li>{@doc SwaggerItemsObject Items}
1028    *    <li>{@doc SwaggerHeaderObject Header}
1029    * </ul>
1030    *
1031    * @param value
1032    *    The new value for this property.
1033    *    <br>Ignored if value is <jk>null</jk>.
1034    * @return This object (for method chaining).
1035    */
1036   public HttpPartSchemaBuilder exclusiveMinimum(Boolean value) {
1037      exclusiveMinimum = resolve(value, exclusiveMinimum);
1038      return this;
1039   }
1040
1041   /**
1042    * <mk>exclusiveMinimum</mk> field.
1043    *
1044    * <p>
1045    * Same as {@link #exclusiveMinimum(Boolean)} but takes in a string boolean value.
1046    *
1047    * @param value
1048    *    The new value for this property.
1049    *    <br>Ignored if value is <jk>null</jk> or empty.
1050    * @return This object (for method chaining).
1051    */
1052   public HttpPartSchemaBuilder exclusiveMinimum(String value) {
1053      exclusiveMinimum = resolve(value, exclusiveMinimum);
1054      return this;
1055   }
1056
1057   /**
1058    * <mk>exclusiveMinimum</mk> field.
1059    *
1060    * <p>
1061    * Shortcut for calling <code>exclusiveMinimum(<jk>true</jk>);</code>.
1062    *
1063    * @return This object (for method chaining).
1064    */
1065   public HttpPartSchemaBuilder exclusiveMinimum() {
1066      return exclusiveMinimum(true);
1067   }
1068
1069   /**
1070    * <mk>maxLength</mk> field.
1071    *
1072    * <p>
1073    * A string instance is valid against this keyword if its length is less than, or equal to, the value of this keyword.
1074    * <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>.
1075    *
1076    * <p>
1077    * Only allowed for the following types: <js>"string"</js>.
1078    *
1079    * <p>
1080    * Applicable to the following Swagger schema objects:
1081    * <ul>
1082    *    <li>{@doc SwaggerParameterObject Parameter}
1083    *    <li>{@doc SwaggerSchemaObject Schema}
1084    *    <li>{@doc SwaggerItemsObject Items}
1085    *    <li>{@doc SwaggerHeaderObject Header}
1086    * </ul>
1087    *
1088    * @param value
1089    *    The new value for this property.
1090    *    <br>Ignored if value is <jk>null</jk> or <code>-1</code>.
1091    * @return This object (for method chaining).
1092    */
1093   public HttpPartSchemaBuilder maxLength(Long value) {
1094      maxLength = resolve(value, maxLength);
1095      return this;
1096   }
1097
1098   /**
1099    * <mk>maxLength</mk> field.
1100    *
1101    * <p>
1102    * Same as {@link #maxLength(Long)} but takes in a string number.
1103    *
1104    * @param value
1105    *    The new value for this property.
1106    *    <br>Ignored if value is <jk>null</jk> or empty.
1107    * @return This object (for method chaining).
1108    */
1109   public HttpPartSchemaBuilder maxLength(String value) {
1110      maxLength = resolve(value, maxLength);
1111      return this;
1112   }
1113
1114   /**
1115    * <mk>minLength</mk> field.
1116    *
1117    * <p>
1118    * A string instance is valid against this keyword if its length is greater than, or equal to, the value of this keyword.
1119    * <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>.
1120    *
1121    * <p>
1122    * Only allowed for the following types: <js>"string"</js>.
1123    *
1124    * <p>
1125    * Applicable to the following Swagger schema objects:
1126    * <ul>
1127    *    <li>{@doc SwaggerParameterObject Parameter}
1128    *    <li>{@doc SwaggerSchemaObject Schema}
1129    *    <li>{@doc SwaggerItemsObject Items}
1130    *    <li>{@doc SwaggerHeaderObject Header}
1131    * </ul>
1132    *
1133    * @param value
1134    *    The new value for this property.
1135    *    <br>Ignored if value is <jk>null</jk> or <code>-1</code>.
1136    * @return This object (for method chaining).
1137    */
1138   public HttpPartSchemaBuilder minLength(Long value) {
1139      minLength = resolve(value, minLength);
1140      return this;
1141   }
1142
1143   /**
1144    * <mk>minLength</mk> field.
1145    *
1146    * <p>
1147    * Same as {@link #minLength(Long)} but takes in a string number.
1148    *
1149    * @param value
1150    *    The new value for this property.
1151    *    <br>Ignored if value is <jk>null</jk> or empty.
1152    * @return This object (for method chaining).
1153    */
1154   public HttpPartSchemaBuilder minLength(String value) {
1155      minLength = resolve(value, minLength);
1156      return this;
1157   }
1158
1159   /**
1160    * <mk>pattern</mk> field.
1161    *
1162    * <p>
1163    * A string input is valid if it matches the specified regular expression pattern.
1164    *
1165    * <p>
1166    * Only allowed for the following types: <js>"string"</js>.
1167    *
1168    * <p>
1169    * Applicable to the following Swagger schema objects:
1170    * <ul>
1171    *    <li>{@doc SwaggerParameterObject Parameter}
1172    *    <li>{@doc SwaggerSchemaObject Schema}
1173    *    <li>{@doc SwaggerItemsObject Items}
1174    *    <li>{@doc SwaggerHeaderObject Header}
1175    * </ul>
1176    *
1177    * @param value
1178    *    The new value for this property.
1179    *    <br>Ignored if value is <jk>null</jk> or empty.
1180    * @return This object (for method chaining).
1181    */
1182   public HttpPartSchemaBuilder pattern(String value) {
1183      try {
1184         if (isNotEmpty(value))
1185            this.pattern = Pattern.compile(value);
1186      } catch (Exception e) {
1187         throw new ContextRuntimeException(e, "Invalid value {0} passed in as pattern value.  Must be a valid regular expression.", value);
1188      }
1189      return this;
1190   }
1191
1192   /**
1193    * <mk>maxItems</mk> field.
1194    *
1195    * <p>
1196    * An array or collection is valid if its size is less than, or equal to, the value of this keyword.
1197    *
1198    * <p>
1199    * Only allowed for the following types: <js>"array"</js>.
1200    *
1201    * <p>
1202    * Applicable to the following Swagger schema objects:
1203    * <ul>
1204    *    <li>{@doc SwaggerParameterObject Parameter}
1205    *    <li>{@doc SwaggerSchemaObject Schema}
1206    *    <li>{@doc SwaggerItemsObject Items}
1207    *    <li>{@doc SwaggerHeaderObject Header}
1208    * </ul>
1209    *
1210    * @param value
1211    *    The new value for this property.
1212    *    <br>Ignored if value is <jk>null</jk> or <code>-1</code>.
1213    * @return This object (for method chaining).
1214    */
1215   public HttpPartSchemaBuilder maxItems(Long value) {
1216      maxItems = resolve(value, maxItems);
1217      return this;
1218   }
1219
1220   /**
1221    * <mk>maxItems</mk> field.
1222    *
1223    * <p>
1224    * Same as {@link #maxItems(Long)} but takes in a string number.
1225    *
1226    * @param value
1227    *    The new value for this property.
1228    *    <br>Ignored if value is <jk>null</jk> or empty.
1229    * @return This object (for method chaining).
1230    */
1231   public HttpPartSchemaBuilder maxItems(String value) {
1232      maxItems = resolve(value, maxItems);
1233      return this;
1234   }
1235
1236   /**
1237    * <mk>minItems</mk> field.
1238    *
1239    * <p>
1240    * An array or collection is valid if its size is greater than, or equal to, the value of this keyword.
1241    *
1242    * <p>
1243    * Only allowed for the following types: <js>"array"</js>.
1244    *
1245    * <p>
1246    * Applicable to the following Swagger schema objects:
1247    * <ul>
1248    *    <li>{@doc SwaggerParameterObject Parameter}
1249    *    <li>{@doc SwaggerSchemaObject Schema}
1250    *    <li>{@doc SwaggerItemsObject Items}
1251    *    <li>{@doc SwaggerHeaderObject Header}
1252    * </ul>
1253    *
1254    * @param value
1255    *    The new value for this property.
1256    *    <br>Ignored if value is <jk>null</jk> or <code>-1<code>.
1257    * @return This object (for method chaining).
1258    */
1259   public HttpPartSchemaBuilder minItems(Long value) {
1260      minItems = resolve(value, minItems);
1261      return this;
1262   }
1263
1264   /**
1265    * <mk>minItems</mk> field.
1266    *
1267    * <p>
1268    * Same as {@link #minItems(Long)} but takes in a string number.
1269    *
1270    * @param value
1271    *    The new value for this property.
1272    *    <br>Ignored if value is <jk>null</jk> or empty.
1273    * @return This object (for method chaining).
1274    */
1275   public HttpPartSchemaBuilder minItems(String value) {
1276      minItems = resolve(value, minItems);
1277      return this;
1278   }
1279
1280   /**
1281    * <mk>uniqueItems</mk> field.
1282    *
1283    * <p>
1284    * If <jk>true</jk>, the input validates successfully if all of its elements are unique.
1285    *
1286    * <p>
1287    * <br>If the parameter type is a subclass of {@link Set}, this validation is skipped (since a set can only contain unique items anyway).
1288    * <br>Otherwise, the collection or array is checked for duplicate items.
1289    *
1290    * <p>
1291    * Only allowed for the following types: <js>"array"</js>.
1292    *
1293    * <p>
1294    * Applicable to the following Swagger schema objects:
1295    * <ul>
1296    *    <li>{@doc SwaggerParameterObject Parameter}
1297    *    <li>{@doc SwaggerSchemaObject Schema}
1298    *    <li>{@doc SwaggerItemsObject Items}
1299    *    <li>{@doc SwaggerHeaderObject Header}
1300    * </ul>
1301    *
1302    * @param value
1303    *    The new value for this property.
1304    *    <br>Ignored if value is <jk>null</jk>.
1305    * @return This object (for method chaining).
1306    */
1307   public HttpPartSchemaBuilder uniqueItems(Boolean value) {
1308      uniqueItems = resolve(value, uniqueItems);
1309      return this;
1310   }
1311
1312   /**
1313    * <mk>uniqueItems</mk> field.
1314    *
1315    * <p>
1316    * Same as {@link #uniqueItems(Boolean)} but takes in a string boolean.
1317    *
1318    * @param value
1319    *    The new value for this property.
1320    *    <br>Ignored if value is <jk>null</jk> or empty..
1321    * @return This object (for method chaining).
1322    */
1323   public HttpPartSchemaBuilder uniqueItems(String value) {
1324      uniqueItems = resolve(value, uniqueItems);
1325      return this;
1326   }
1327
1328   /**
1329    * <mk>uniqueItems</mk> field.
1330    *
1331    * <p>
1332    * Shortcut for calling <code>uniqueItems(<jk>true</jk>);</code>.
1333    *
1334    * @return This object (for method chaining).
1335    */
1336   public HttpPartSchemaBuilder uniqueItems() {
1337      return uniqueItems(true);
1338   }
1339
1340   /**
1341    * <mk>skipIfEmpty</mk> field.
1342    *
1343    * <p>
1344    * Identifies whether an item should be skipped during serialization if it's empty.
1345    *
1346    * @param value
1347    *    The new value for this property.
1348    *    <br>Ignored if value is <jk>null</jk>.
1349    * @return This object (for method chaining).
1350    */
1351   public HttpPartSchemaBuilder skipIfEmpty(Boolean value) {
1352      skipIfEmpty = resolve(value, skipIfEmpty);
1353      return this;
1354   }
1355
1356   /**
1357    * <mk>skipIfEmpty</mk> field.
1358    *
1359    * <p>
1360    * Same as {@link #skipIfEmpty(Boolean)} but takes in a string boolean.
1361    *
1362    * @param value
1363    *    The new value for this property.
1364    *    <br>Ignored if value is <jk>null</jk> or empty.
1365    * @return This object (for method chaining).
1366    */
1367   public HttpPartSchemaBuilder skipIfEmpty(String value) {
1368      skipIfEmpty = resolve(value, skipIfEmpty);
1369      return this;
1370   }
1371
1372   /**
1373    * Identifies whether an item should be skipped if it's empty.
1374    *
1375    * <p>
1376    * Shortcut for calling <code>skipIfEmpty(<jk>true</jk>);</code>.
1377    *
1378    * @return This object (for method chaining).
1379    */
1380   public HttpPartSchemaBuilder skipIfEmpty() {
1381      return skipIfEmpty(true);
1382   }
1383
1384   /**
1385    * <mk>enum</mk> field.
1386    *
1387    * <p>
1388    * If specified, the input validates successfully if it is equal to one of the elements in this array.
1389    *
1390    * <p>
1391    * Applicable to the following Swagger schema objects:
1392    * <ul>
1393    *    <li>{@doc SwaggerParameterObject Parameter}
1394    *    <li>{@doc SwaggerSchemaObject Schema}
1395    *    <li>{@doc SwaggerItemsObject Items}
1396    *    <li>{@doc SwaggerHeaderObject Header}
1397    * </ul>
1398    *
1399    * @param value
1400    *    The new value for this property.
1401    *    <br>Ignored if value is <jk>null</jk> or an empty set.
1402    * @return This object (for method chaining).
1403    */
1404   public HttpPartSchemaBuilder _enum(Set<String> value) {
1405      if (value != null && ! value.isEmpty())
1406         this._enum = value;
1407      return this;
1408   }
1409
1410   /**
1411    * <mk>_enum</mk> field.
1412    *
1413    * <p>
1414    * Same as {@link #_enum(Set)} but takes in a var-args array.
1415    *
1416    * @param values
1417    *    The new values for this property.
1418    *    <br>Ignored if value is empty.
1419    * @return This object (for method chaining).
1420    */
1421   public HttpPartSchemaBuilder _enum(String...values) {
1422      return _enum(new ASet<String>().appendAll(values));
1423   }
1424
1425   /**
1426    * <mk>multipleOf</mk> field.
1427    *
1428    * <p>
1429    * A numeric instance is valid if the result of the division of the instance by this keyword's value is an integer.
1430    *
1431    * <p>
1432    * Only allowed for the following types: <js>"integer"</js>, <js>"number"</js>.
1433    *
1434    * <p>
1435    * Applicable to the following Swagger schema objects:
1436    * <ul>
1437    *    <li>{@doc SwaggerParameterObject Parameter}
1438    *    <li>{@doc SwaggerSchemaObject Schema}
1439    *    <li>{@doc SwaggerItemsObject Items}
1440    *    <li>{@doc SwaggerHeaderObject Header}
1441    * </ul>
1442    *
1443    * @param value
1444    *    The new value for this property.
1445    *    <br>Ignored if value is <jk>null</jk>.
1446    * @return This object (for method chaining).
1447    */
1448   public HttpPartSchemaBuilder multipleOf(Number value) {
1449      if (value != null)
1450         this.multipleOf = value;
1451      return this;
1452   }
1453
1454   /**
1455    * <mk>mapProperties</mk> field.
1456    *
1457    * <p>
1458    * Applicable to the following Swagger schema objects:
1459    * <ul>
1460    *    <li>{@doc SwaggerSchemaObject Schema}
1461    * </ul>
1462    *
1463    * @param value
1464    *    The new value for this property.
1465    *    <br>Ignored if value is <jk>null</jk> or <code>-1</code>.
1466    * @return This object (for method chaining).
1467    */
1468   public HttpPartSchemaBuilder maxProperties(Long value) {
1469      maxProperties = resolve(value, maxProperties);
1470      return this;
1471   }
1472
1473   /**
1474    * <mk>mapProperties</mk> field.
1475    *
1476    * <p>
1477    * Same as {@link #maxProperties(Long)} but takes in a string number.
1478    *
1479    * @param value
1480    *    The new value for this property.
1481    *    <br>Ignored if value is <jk>null</jk> or empty.
1482    * @return This object (for method chaining).
1483    */
1484   public HttpPartSchemaBuilder maxProperties(String value) {
1485      maxProperties = resolve(value, maxProperties);
1486      return this;
1487   }
1488
1489   /**
1490    * <mk>minProperties</mk> field.
1491    *
1492    * <p>
1493    * Applicable to the following Swagger schema objects:
1494    * <ul>
1495    *    <li>{@doc SwaggerSchemaObject Schema}
1496    * </ul>
1497    *
1498    * @param value
1499    *    The new value for this property.
1500    *    <br>Ignored if value is <jk>null</jk>.
1501    * @return This object (for method chaining).
1502    */
1503   public HttpPartSchemaBuilder minProperties(Long value) {
1504      minProperties = resolve(value, minProperties);
1505      return this;
1506   }
1507
1508   /**
1509    * <mk>minProperties</mk> field.
1510    *
1511    * <p>
1512    * Same as {@link #minProperties(Long)} but takes in a string boolean.
1513    *
1514    * @param value
1515    *    The new value for this property.
1516    *    <br>Ignored if value is <jk>null</jk> or empty.
1517    * @return This object (for method chaining).
1518    */
1519   public HttpPartSchemaBuilder minProperties(String value) {
1520      minProperties = resolve(value, minProperties);
1521      return this;
1522   }
1523
1524   /**
1525    * <mk>properties</mk> field.
1526    *
1527    * <p>
1528    * Applicable to the following Swagger schema objects:
1529    * <ul>
1530    *    <li>{@doc SwaggerSchemaObject Schema}
1531    * </ul>
1532    *
1533    * @param key
1534    * The property name.
1535    * @param value
1536    *    The new value for this property.
1537    *    <br>Ignored if value is <jk>null</jk>.
1538    * @return This object (for method chaining).
1539    */
1540   public HttpPartSchemaBuilder property(String key, HttpPartSchemaBuilder value) {
1541      if ( key != null && value != null) {
1542         if (properties == null)
1543            properties = new LinkedHashMap<>();
1544         properties.put(key, value);
1545      }
1546      return this;
1547   }
1548
1549   private HttpPartSchemaBuilder properties(ObjectMap value) {
1550      if (value != null && ! value.isEmpty())
1551      for (Map.Entry<String,Object> e : value.entrySet())
1552         property(e.getKey(), HttpPartSchema.create().apply((ObjectMap)e.getValue()));
1553      return this;
1554   }
1555
1556   /**
1557    * <mk>additionalProperties</mk> field.
1558    *
1559    * <p>
1560    * Applicable to the following Swagger schema objects:
1561    * <ul>
1562    *    <li>{@doc SwaggerSchemaObject Schema}
1563    * </ul>
1564    *
1565    * @param value
1566    *    The new value for this property.
1567    *    <br>Ignored if value is <jk>null</jk> or empty.
1568    * @return This object (for method chaining).
1569    */
1570   public HttpPartSchemaBuilder additionalProperties(HttpPartSchemaBuilder value) {
1571      if (value != null)
1572         additionalProperties = value;
1573      return this;
1574   }
1575
1576   private HttpPartSchemaBuilder additionalProperties(ObjectMap value) {
1577      if (value != null && ! value.isEmpty())
1578         additionalProperties = HttpPartSchema.create().apply(value);
1579      return this;
1580   }
1581
1582   /**
1583    * Identifies the part serializer to use for serializing this part.
1584    *
1585    * @param value
1586    *    The new value for this property.
1587    *    <br>Ignored if value is <jk>null</jk> or {@link HttpPartSerializer.Null}.
1588    * @return This object (for method chaining).
1589    */
1590   public HttpPartSchemaBuilder serializer(Class<? extends HttpPartSerializer> value) {
1591      if (value != null && value != HttpPartSerializer.Null.class)
1592         serializer = value;
1593      return this;
1594   }
1595
1596   /**
1597    * Identifies the part parser to use for parsing this part.
1598    *
1599    * @param value
1600    *    The new value for this property.
1601    *    <br>Ignored if value is <jk>null</jk> or {@link HttpPartParser.Null}.
1602    * @return This object (for method chaining).
1603    */
1604   public HttpPartSchemaBuilder parser(Class<? extends HttpPartParser> value) {
1605      if (value != null && value != HttpPartParser.Null.class)
1606         parser = value;
1607      return this;
1608   }
1609
1610   /**
1611    * Disables Swagger schema usage validation checking.
1612    *
1613    * @param value Specify <jk>true</jk> to prevent {@link ContextRuntimeException} from being thrown if invalid Swagger usage was detected.
1614    * @return This object (for method chaining).
1615    */
1616   public HttpPartSchemaBuilder noValidate(Boolean value) {
1617      if (value != null)
1618         this.noValidate = value;
1619      return this;
1620   }
1621
1622   /**
1623    * Disables Swagger schema usage validation checking.
1624    *
1625    * <p>
1626    * Shortcut for calling <code>noValidate(<jk>true</jk>);</code>.
1627    *
1628    * @return This object (for method chaining).
1629    */
1630   public HttpPartSchemaBuilder noValidate() {
1631      return noValidate(true);
1632   }
1633
1634   private Boolean resolve(String newValue, Boolean oldValue) {
1635      return isEmpty(newValue) ? oldValue : Boolean.valueOf(newValue);
1636   }
1637
1638   private Boolean resolve(Boolean newValue, Boolean oldValue) {
1639      return newValue == null ? oldValue : newValue;
1640   }
1641
1642   private Long resolve(String newValue, Long oldValue) {
1643      return isEmpty(newValue) ? oldValue : Long.parseLong(newValue);
1644   }
1645
1646   private Long resolve(Long newValue, Long oldValue) {
1647      return (newValue == null || newValue == -1) ? oldValue : newValue;
1648   }
1649}