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