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.*;
016import java.lang.annotation.*;
017import java.lang.reflect.*;
018import java.util.*;
019import java.util.regex.*;
020
021import org.apache.juneau.*;
022import org.apache.juneau.http.annotation.*;
023import org.apache.juneau.jsonschema.annotation.Schema;
024import org.apache.juneau.jsonschema.annotation.Items;
025import org.apache.juneau.jsonschema.annotation.SubItems;
026import org.apache.juneau.reflect.*;
027import org.apache.juneau.httppart.HttpPartSchema.*;
028import org.apache.juneau.httppart.HttpPartSchema.Type;
029import org.apache.juneau.utils.*;
030
031/**
032 * The builder class for creating {@link HttpPartSchema} objects.
033 *
034 */
035public class HttpPartSchemaBuilder {
036   String name, _default;
037   Set<Integer> codes;
038   Set<String> _enum;
039   Boolean allowEmptyValue, exclusiveMaximum, exclusiveMinimum, required, uniqueItems, skipIfEmpty;
040   CollectionFormat collectionFormat = CollectionFormat.NO_COLLECTION_FORMAT;
041   Type type = Type.NO_TYPE;
042   Format format = Format.NO_FORMAT;
043   Pattern pattern;
044   Number maximum, minimum, multipleOf;
045   Long maxLength, minLength, maxItems, minItems, maxProperties, minProperties;
046   Map<String,HttpPartSchemaBuilder> properties;
047   HttpPartSchemaBuilder items, additionalProperties;
048   boolean noValidate;
049   Class<? extends HttpPartParser> parser;
050   Class<? extends HttpPartSerializer> serializer;
051
052   /**
053    * Instantiates a new {@link HttpPartSchema} object based on the configuration of this builder.
054    *
055    * <p>
056    * This method can be called multiple times to produce new schema objects.
057    *
058    * @return
059    *    A new {@link HttpPartSchema} object.
060    *    <br>Never <jk>null</jk>.
061    */
062   public HttpPartSchema build() {
063      return new HttpPartSchema(this);
064   }
065
066   HttpPartSchemaBuilder apply(Class<? extends Annotation> c, ParamInfo mpi) {
067      apply(c, mpi.getParameterType().innerType());
068      for (Annotation a : mpi.getDeclaredAnnotations())
069         if (c.isInstance(a))
070            apply(a);
071      return this;
072   }
073
074   HttpPartSchemaBuilder apply(Class<? extends Annotation> c, Method m) {
075      apply(c, m.getGenericReturnType());
076      Annotation a = m.getAnnotation(c);
077      if (a != null)
078         return apply(a);
079      return this;
080   }
081
082   HttpPartSchemaBuilder apply(Class<? extends Annotation> c, java.lang.reflect.Type t) {
083      if (t instanceof Class<?>) {
084         ClassInfo ci = ClassInfo.of((Class<?>)t);
085         for (Annotation a : ci.getAnnotationsParentFirst(c))
086            apply(a);
087      } else if (Value.isType(t)) {
088         apply(c, Value.getParameterType(t));
089      }
090      return this;
091   }
092
093   /**
094    * Apply the specified annotation to this schema.
095    *
096    * @param a The annotation to apply.
097    * @return This object (for method chaining).
098    */
099   public HttpPartSchemaBuilder apply(Annotation a) {
100      if (a instanceof Body)
101         apply((Body)a);
102      else if (a instanceof Header)
103         apply((Header)a);
104      else if (a instanceof FormData)
105         apply((FormData)a);
106      else if (a instanceof Query)
107         apply((Query)a);
108      else if (a instanceof Path)
109         apply((Path)a);
110      else if (a instanceof Response)
111         apply((Response)a);
112      else if (a instanceof ResponseHeader)
113         apply((ResponseHeader)a);
114      else if (a instanceof HasQuery)
115         apply((HasQuery)a);
116      else if (a instanceof HasFormData)
117         apply((HasFormData)a);
118      else if (a instanceof Schema)
119         apply((Schema)a);
120      else
121         throw new RuntimeException("HttpPartSchemaBuilder.apply(@"+a.getClass().getSimpleName()+") not defined");
122      return this;
123   }
124
125   HttpPartSchemaBuilder apply(Body a) {
126      required(a.required());
127      allowEmptyValue(! a.required());
128      apply(a.schema());
129      return this;
130   }
131
132   HttpPartSchemaBuilder apply(Header a) {
133      name(a.value());
134      name(a.name());
135      required(a.required());
136      type(a.type());
137      format(a.format());
138      allowEmptyValue(a.allowEmptyValue());
139      items(a.items());
140      collectionFormat(a.collectionFormat());
141      _default(a._default().length == 0 ? null : joinnl(a._default()));
142      maximum(HttpPartSchema.toNumber(a.maximum()));
143      exclusiveMaximum(a.exclusiveMaximum());
144      minimum(HttpPartSchema.toNumber(a.minimum()));
145      exclusiveMinimum(a.exclusiveMinimum());
146      maxLength(a.maxLength());
147      minLength(a.minLength());
148      pattern(a.pattern());
149      maxItems(a.maxItems());
150      minItems(a.minItems());
151      uniqueItems(a.uniqueItems());
152      _enum(HttpPartSchema.toSet(a._enum()));
153      multipleOf(HttpPartSchema.toNumber(a.multipleOf()));
154      skipIfEmpty(a.skipIfEmpty());
155      parser(a.parser());
156      serializer(a.serializer());
157      return this;
158   }
159
160   HttpPartSchemaBuilder apply(ResponseHeader a) {
161      name(a.value());
162      name(a.name());
163      codes(a.code());
164      type(a.type());
165      format(a.format());
166      items(a.items());
167      collectionFormat(a.collectionFormat());
168      _default(a._default().length == 0 ? null : joinnl(a._default()));
169      maximum(HttpPartSchema.toNumber(a.maximum()));
170      exclusiveMaximum(a.exclusiveMaximum());
171      minimum(HttpPartSchema.toNumber(a.minimum()));
172      exclusiveMinimum(a.exclusiveMinimum());
173      maxLength(a.maxLength());
174      minLength(a.minLength());
175      pattern(a.pattern());
176      maxItems(a.maxItems());
177      minItems(a.minItems());
178      uniqueItems(a.uniqueItems());
179      _enum(HttpPartSchema.toSet(a._enum()));
180      multipleOf(HttpPartSchema.toNumber(a.multipleOf()));
181      allowEmptyValue(false);
182      serializer(a.serializer());
183      return this;
184   }
185
186   HttpPartSchemaBuilder apply(FormData a) {
187      name(a.value());
188      name(a.name());
189      required(a.required());
190      type(a.type());
191      format(a.format());
192      allowEmptyValue(a.allowEmptyValue());
193      items(a.items());
194      collectionFormat(a.collectionFormat());
195      _default(a._default().length == 0 ? null : joinnl(a._default()));
196      maximum(HttpPartSchema.toNumber(a.maximum()));
197      exclusiveMaximum(a.exclusiveMaximum());
198      minimum(HttpPartSchema.toNumber(a.minimum()));
199      exclusiveMinimum(a.exclusiveMinimum());
200      maxLength(a.maxLength());
201      minLength(a.minLength());
202      pattern(a.pattern());
203      maxItems(a.maxItems());
204      minItems(a.minItems());
205      uniqueItems(a.uniqueItems());
206      _enum(HttpPartSchema.toSet(a._enum()));
207      multipleOf(HttpPartSchema.toNumber(a.multipleOf()));
208      skipIfEmpty(a.skipIfEmpty());
209      parser(a.parser());
210      serializer(a.serializer());
211      return this;
212   }
213
214   HttpPartSchemaBuilder apply(Query a) {
215      name(a.value());
216      name(a.name());
217      required(a.required());
218      type(a.type());
219      format(a.format());
220      allowEmptyValue(a.allowEmptyValue());
221      items(a.items());
222      collectionFormat(a.collectionFormat());
223      _default(a._default().length == 0 ? null : joinnl(a._default()));
224      maximum(HttpPartSchema.toNumber(a.maximum()));
225      exclusiveMaximum(a.exclusiveMaximum());
226      minimum(HttpPartSchema.toNumber(a.minimum()));
227      exclusiveMinimum(a.exclusiveMinimum());
228      maxLength(a.maxLength());
229      minLength(a.minLength());
230      pattern(a.pattern());
231      maxItems(a.maxItems());
232      minItems(a.minItems());
233      uniqueItems(a.uniqueItems());
234      _enum(HttpPartSchema.toSet(a._enum()));
235      multipleOf(HttpPartSchema.toNumber(a.multipleOf()));
236      skipIfEmpty(a.skipIfEmpty());
237      parser(a.parser());
238      serializer(a.serializer());
239      return this;
240   }
241
242   HttpPartSchemaBuilder apply(Path a) {
243      name(a.value());
244      name(a.name());
245      type(a.type());
246      format(a.format());
247      items(a.items());
248      allowEmptyValue(a.allowEmptyValue());
249      collectionFormat(a.collectionFormat());
250      maximum(HttpPartSchema.toNumber(a.maximum()));
251      exclusiveMaximum(a.exclusiveMaximum());
252      minimum(HttpPartSchema.toNumber(a.minimum()));
253      exclusiveMinimum(a.exclusiveMinimum());
254      maxLength(a.maxLength());
255      minLength(a.minLength());
256      pattern(a.pattern());
257      maxItems(a.maxItems());
258      minItems(a.minItems());
259      uniqueItems(a.uniqueItems());
260      _enum(HttpPartSchema.toSet(a._enum()));
261      multipleOf(HttpPartSchema.toNumber(a.multipleOf()));
262      parser(a.parser());
263      serializer(a.serializer());
264
265      // Path remainder always allows empty value.
266      if (startsWith(name, '/'))
267         allowEmptyValue();
268      else
269         required(true);
270
271      return this;
272   }
273
274   HttpPartSchemaBuilder apply(Response a) {
275      codes(a.value());
276      codes(a.code());
277      required(false);
278      allowEmptyValue(true);
279      serializer(a.partSerializer());
280      parser(a.partParser());
281      apply(a.schema());
282      return this;
283   }
284
285   HttpPartSchemaBuilder apply(Items a) {
286      type(a.type());
287      format(a.format());
288      items(a.items());
289      collectionFormat(a.collectionFormat());
290      _default(a._default().length == 0 ? null : joinnl(a._default()));
291      maximum(HttpPartSchema.toNumber(a.maximum()));
292      exclusiveMaximum(a.exclusiveMaximum());
293      minimum(HttpPartSchema.toNumber(a.minimum()));
294      exclusiveMinimum(a.exclusiveMinimum());
295      maxLength(a.maxLength());
296      minLength(a.minLength());
297      pattern(a.pattern());
298      maxItems(a.maxItems());
299      minItems(a.minItems());
300      uniqueItems(a.uniqueItems());
301      _enum(HttpPartSchema.toSet(a._enum()));
302      multipleOf(HttpPartSchema.toNumber(a.multipleOf()));
303      return this;
304   }
305
306   HttpPartSchemaBuilder apply(SubItems a) {
307      type(a.type());
308      format(a.format());
309      items(HttpPartSchema.toObjectMap(a.items()));
310      collectionFormat(a.collectionFormat());
311      _default(a._default().length == 0 ? null : joinnl(a._default()));
312      maximum(HttpPartSchema.toNumber(a.maximum()));
313      exclusiveMaximum(a.exclusiveMaximum());
314      minimum(HttpPartSchema.toNumber(a.minimum()));
315      exclusiveMinimum(a.exclusiveMinimum());
316      maxLength(a.maxLength());
317      minLength(a.minLength());
318      pattern(a.pattern());
319      maxItems(a.maxItems());
320      minItems(a.minItems());
321      uniqueItems(a.uniqueItems());
322      _enum(HttpPartSchema.toSet(a._enum()));
323      multipleOf(HttpPartSchema.toNumber(a.multipleOf()));
324      return this;
325   }
326
327   HttpPartSchemaBuilder apply(Schema a) {
328      type(a.type());
329      format(a.format());
330      items(a.items());
331      collectionFormat(a.collectionFormat());
332      _default(a._default().length == 0 ? null : joinnl(a._default()));
333      maximum(HttpPartSchema.toNumber(a.maximum()));
334      exclusiveMaximum(a.exclusiveMaximum());
335      minimum(HttpPartSchema.toNumber(a.minimum()));
336      exclusiveMinimum(a.exclusiveMinimum());
337      maxLength(a.maxLength());
338      minLength(a.minLength());
339      pattern(a.pattern());
340      maxItems(a.maxItems());
341      minItems(a.minItems());
342      uniqueItems(a.uniqueItems());
343      _enum(HttpPartSchema.toSet(a._enum()));
344      multipleOf(HttpPartSchema.toNumber(a.multipleOf()));
345      maxProperties(a.maxProperties());
346      minProperties(a.minProperties());
347      properties(HttpPartSchema.toObjectMap(a.properties()));
348      additionalProperties(HttpPartSchema.toObjectMap(a.additionalProperties()));
349      return this;
350   }
351
352   HttpPartSchemaBuilder apply(HasQuery a) {
353      name(a.value());
354      name(a.name());
355      return this;
356   }
357
358   HttpPartSchemaBuilder apply(HasFormData a) {
359      name(a.value());
360      name(a.name());
361      return this;
362   }
363
364   HttpPartSchemaBuilder apply(ObjectMap m) {
365      if (m != null && ! m.isEmpty()) {
366         _default(m.getString("default"));
367         _enum(HttpPartSchema.toSet(m.getString("enum")));
368         allowEmptyValue(m.getBoolean("allowEmptyValue"));
369         exclusiveMaximum(m.getBoolean("exclusiveMaximum"));
370         exclusiveMinimum(m.getBoolean("exclusiveMinimum"));
371         required(m.getBoolean("required"));
372         uniqueItems(m.getBoolean("uniqueItems"));
373         collectionFormat(m.getString("collectionFormat"));
374         type(m.getString("type"));
375         format(m.getString("format"));
376         pattern(m.getString("pattern"));
377         maximum(m.get("maximum", Number.class));
378         minimum(m.get("minimum", Number.class));
379         multipleOf(m.get("multipleOf", Number.class));
380         maxItems(m.get("maxItems", Long.class));
381         maxLength(m.get("maxLength", Long.class));
382         maxProperties(m.get("maxProperties", Long.class));
383         minItems(m.get("minItems", Long.class));
384         minLength(m.get("minLength", Long.class));
385         minProperties(m.get("minProperties", Long.class));
386
387         items(m.getObjectMap("items"));
388         properties(m.getObjectMap("properties"));
389         additionalProperties(m.getObjectMap("additionalProperties"));
390
391         apply(m.getObjectMap("schema", null));
392      }
393      return this;
394   }
395
396   /**
397    * <mk>name</mk> field.
398    *
399    * <p>
400    * Applicable to the following Swagger schema objects:
401    * <ul>
402    *    <li>{@doc SwaggerParameterObject Parameter}
403    *    <li>{@doc SwaggerHeaderObject Header}
404    * </ul>
405    *
406    * @param value
407    *    The new value for this property.
408    * @return This object (for method chaining).
409    */
410   public HttpPartSchemaBuilder name(String value) {
411      if (isNotEmpty(value))
412         name = value;
413      return this;
414   }
415
416   /**
417    * <mk>httpStatusCode</mk> key.
418    *
419    * <p>
420    * Applicable to the following Swagger schema objects:
421    * <ul>
422    *    <li>{@doc SwaggerResponsesObject Responses}
423    * </ul>
424    *
425    * @param value
426    *    The new value for this property.
427    *    <br>Ignored if <jk>null</jk> or an empty array.
428    * @return This object (for method chaining).
429    */
430   public HttpPartSchemaBuilder codes(int[] value) {
431      if (value != null && value.length != 0)
432         for (int v : value)
433            code(v);
434      return this;
435   }
436
437   /**
438    * <mk>httpStatusCode</mk> key.
439    *
440    * <p>
441    * Applicable to the following Swagger schema objects:
442    * <ul>
443    *    <li>{@doc SwaggerResponsesObject Responses}
444    * </ul>
445    *
446    * @param value
447    *    The new value for this property.
448    *    <br>Ignored if value is <c>0</c>.
449    * @return This object (for method chaining).
450    */
451   public HttpPartSchemaBuilder code(int value) {
452      if (value != 0) {
453         if (codes == null)
454            codes = new TreeSet<>();
455         codes.add(value);
456      }
457      return this;
458   }
459
460   /**
461    * <mk>required</mk> field.
462    *
463    * <p>
464    * Determines whether the parameter is mandatory.
465    *
466    * <p>
467    * Applicable to the following Swagger schema objects:
468    * <ul>
469    *    <li>{@doc SwaggerParameterObject Parameter}
470    *    <li>{@doc SwaggerSchemaObject Schema}
471    * </ul>
472    *
473    * @param value
474    *    The new value for this property.
475    *    <br>Ignored if value is <jk>null</jk>.
476    * @return This object (for method chaining).
477    */
478   public HttpPartSchemaBuilder required(Boolean value) {
479      required = resolve(value, required);
480      return this;
481   }
482
483   /**
484    * <mk>required</mk> field.
485    *
486    * <p>
487    * Determines whether the parameter is mandatory.
488    *
489    * <p>
490    * Same as {@link #required(Boolean)} but takes in a boolean value as a string.
491    *
492    * @param value
493    *    The new value for this property.
494    *    <br>Ignored if value is <jk>null</jk> or empty.
495    * @return This object (for method chaining).
496    */
497   public HttpPartSchemaBuilder required(String value) {
498      required = resolve(value, required);
499      return this;
500   }
501
502   /**
503    * <mk>required</mk> field.
504    *
505    * <p>
506    * Shortcut for calling <code>required(<jk>true</jk>);</code>.
507    *
508    * @return This object (for method chaining).
509    */
510   public HttpPartSchemaBuilder required() {
511      return required(true);
512   }
513
514   /**
515    * <mk>type</mk> field.
516    *
517    * <p>
518    * The type of the parameter.
519    *
520    * <p>
521    * The possible values are:
522    * <ul class='spaced-list'>
523    *    <li>
524    *       <js>"string"</js>
525    *       <br>Parameter must be a string or a POJO convertible from a string.
526    *    <li>
527    *       <js>"number"</js>
528    *       <br>Parameter must be a number primitive or number object.
529    *       <br>If parameter is <c>Object</c>, creates either a <c>Float</c> or <c>Double</c> depending on the size of the number.
530    *    <li>
531    *       <js>"integer"</js>
532    *       <br>Parameter must be a integer/long primitive or integer/long object.
533    *       <br>If parameter is <c>Object</c>, creates either a <c>Short</c>, <c>Integer</c>, or <c>Long</c> depending on the size of the number.
534    *    <li>
535    *       <js>"boolean"</js>
536    *       <br>Parameter must be a boolean primitive or object.
537    *    <li>
538    *       <js>"array"</js>
539    *       <br>Parameter must be an array or collection.
540    *       <br>Elements must be strings or POJOs convertible from strings.
541    *       <br>If parameter is <c>Object</c>, creates an {@link ObjectList}.
542    *    <li>
543    *       <js>"object"</js>
544    *       <br>Parameter must be a map or bean.
545    *       <br>If parameter is <c>Object</c>, creates an {@link ObjectMap}.
546    *       <br>Note that this is an extension of the OpenAPI schema as Juneau allows for arbitrarily-complex POJOs to be serialized as HTTP parts.
547    *    <li>
548    *       <js>"file"</js>
549    *       <br>This type is currently not supported.
550    * </ul>
551    *
552    * <p>
553    * If the type is not specified, it will be auto-detected based on the parameter class type.
554    *
555    * <p>
556    * Applicable to the following Swagger schema objects:
557    * <ul>
558    *    <li>{@doc SwaggerParameterObject Parameter}
559    *    <li>{@doc SwaggerSchemaObject Schema}
560    *    <li>{@doc SwaggerItemsObject Items}
561    *    <li>{@doc SwaggerSecuritySchemeObject SecurityScheme}
562    * </ul>
563    *
564    * <ul class='seealso'>
565    *    <li class='extlink'>{@doc SwaggerDataTypes}
566    * </ul>
567    *
568    * @param value
569    *    The new value for this property.
570    *    <br>Ignored if value is <jk>null</jk> or empty.
571    * @return This object (for method chaining).
572    */
573   public HttpPartSchemaBuilder type(String value) {
574      try {
575         if (isNotEmpty(value))
576            type = Type.fromString(value);
577      } catch (Exception e) {
578         throw new ContextRuntimeException("Invalid value ''{0}'' passed in as type value.  Valid values: {1}", value, Type.values());
579      }
580      return this;
581   }
582
583   /**
584    * <mk>format</mk> field.
585    *
586    * <p>
587    * The extending format for the previously mentioned {@doc SwaggerParameterTypes parameter type}.
588    *
589    * <p>
590    * The possible values are:
591    * <ul class='spaced-list'>
592    *    <li>
593    *       <js>"int32"</js> - Signed 32 bits.
594    *       <br>Only valid with type <js>"integer"</js>.
595    *    <li>
596    *       <js>"int64"</js> - Signed 64 bits.
597    *       <br>Only valid with type <js>"integer"</js>.
598    *    <li>
599    *       <js>"float"</js> - 32-bit floating point number.
600    *       <br>Only valid with type <js>"number"</js>.
601    *    <li>
602    *       <js>"double"</js> - 64-bit floating point number.
603    *       <br>Only valid with type <js>"number"</js>.
604    *    <li>
605    *       <js>"byte"</js> - BASE-64 encoded characters.
606    *       <br>Only valid with type <js>"string"</js>.
607    *       <br>Parameters of type POJO convertible from string are converted after the string has been decoded.
608    *    <li>
609    *       <js>"binary"</js> - Hexadecimal encoded octets (e.g. <js>"00FF"</js>).
610    *       <br>Only valid with type <js>"string"</js>.
611    *       <br>Parameters of type POJO convertible from string are converted after the string has been decoded.
612    *    <li>
613    *       <js>"binary-spaced"</js> - Hexadecimal encoded octets, spaced (e.g. <js>"00 FF"</js>).
614    *       <br>Only valid with type <js>"string"</js>.
615    *       <br>Parameters of type POJO convertible from string are converted after the string has been decoded.
616    *    <li>
617    *       <js>"date"</js> - An <a href='http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14'>RFC3339 full-date</a>.
618    *       <br>Only valid with type <js>"string"</js>.
619    *    <li>
620    *       <js>"date-time"</js> - An <a href='http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14'>RFC3339 date-time</a>.
621    *       <br>Only valid with type <js>"string"</js>.
622    *    <li>
623    *       <js>"password"</js> - Used to hint UIs the input needs to be obscured.
624    *       <br>This format does not affect the serialization or parsing of the parameter.
625    *    <li>
626    *       <js>"uon"</js> - UON notation (e.g. <js>"(foo=bar,baz=@(qux,123))"</js>).
627    *       <br>Only valid with type <js>"object"</js>.
628    *       <br>If not specified, then the input is interpreted as plain-text and is converted to a POJO directly.
629    * </ul>
630    *
631    * <p>
632    * Applicable to the following Swagger schema objects:
633    * <ul>
634    *    <li>{@doc SwaggerParameterObject Parameter}
635    *    <li>{@doc SwaggerSchemaObject Schema}
636    *    <li>{@doc SwaggerItemsObject Items}
637    *    <li>{@doc SwaggerHeaderObject Header}
638    * </ul>
639    *
640    * <ul class='seealso'>
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 <c>type</c> is <js>"array"</js>.
718    * <br>Can only be used if <c>type</c> 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 <c>type</c> <js>"array"</js> is used.
764    * <br>Can only be used if <c>type</c> 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 <c>maximum</c>.
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 <c>minimum</c>.
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 <c>-1</c>.
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 <c>-1</c>.
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 <c>-1</c>.
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 <c>-1</c>.
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 <c>-1</c>.
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}