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.dto.swagger;
014
015import static org.apache.juneau.internal.BeanPropertyUtils.*;
016import static org.apache.juneau.internal.ArrayUtils.*;
017
018import java.util.*;
019
020import org.apache.juneau.*;
021import org.apache.juneau.annotation.*;
022import org.apache.juneau.internal.*;
023import org.apache.juneau.json.*;
024import org.apache.juneau.utils.*;
025
026/**
027 * A limited subset of JSON-Schema's items object.
028 *
029 * <p>
030 * It is used by parameter definitions that are not located in "body".
031 *
032 * <h5 class='section'>Example:</h5>
033 * <p class='bcode w800'>
034 *    <jc>// Construct using SwaggerBuilder.</jc>
035 *    Items x = <jsm>items</jsm>(<js>"string"</js>).minLength(2);
036 *
037 *    <jc>// Serialize using JsonSerializer.</jc>
038 *    String json = JsonSerializer.<jsf>DEFAULT</jsf>.toString(x);
039 *
040 *    <jc>// Or just use toString() which does the same as above.</jc>
041 *    String json = x.toString();
042 * </p>
043 * <p class='bcode w800'>
044 *    <jc>// Output</jc>
045 *    {
046 *       <js>"type"</js>: <js>"string"</js>,
047 *       <js>"minLength"</js>: 2
048 *    }
049 * </p>
050 *
051 * <h5 class='section'>See Also:</h5>
052 * <ul class='doctree'>
053 *    <li class='link'>{@doc juneau-dto.Swagger}
054 * </ul>
055 */
056@Bean(properties="type,format,items,collectionFormat,default,maximum,exclusiveMaximum,minimum,exclusiveMinimum,maxLength,minLength,pattern,maxItems,minItems,uniqueItems,enum,multipleOf,$ref,*")
057public class Items extends SwaggerElement {
058
059   private static final String[] VALID_TYPES = {"string", "number", "integer", "boolean", "array"};
060   private static final String[] VALID_COLLECTION_FORMATS = {"csv","ssv","tsv","pipes","multi"};
061
062   private String
063      type,
064      format,
065      collectionFormat,
066      pattern,
067      ref;
068   private Number
069      maximum,
070      minimum,
071      multipleOf;
072   private Integer
073      maxLength,
074      minLength,
075      maxItems,
076      minItems;
077   private Boolean
078      exclusiveMaximum,
079      exclusiveMinimum,
080      uniqueItems;
081   private Items items;
082   private Object _default;
083   private List<Object> _enum;
084
085   /**
086    * Default constructor.
087    */
088   public Items() {}
089
090   /**
091    * Copy constructor.
092    *
093    * @param copyFrom The object to copy.
094    */
095   public Items(Items copyFrom) {
096      super(copyFrom);
097
098      this.type = copyFrom.type;
099      this.format = copyFrom.format;
100      this.collectionFormat = copyFrom.collectionFormat;
101      this.pattern = copyFrom.pattern;
102      this.maximum = copyFrom.maximum;
103      this.minimum = copyFrom.minimum;
104      this.multipleOf = copyFrom.multipleOf;
105      this.maxLength = copyFrom.maxLength;
106      this.minLength = copyFrom.minLength;
107      this.maxItems = copyFrom.maxItems;
108      this.minItems = copyFrom.minItems;
109      this.exclusiveMaximum = copyFrom.exclusiveMaximum;
110      this.exclusiveMinimum = copyFrom.exclusiveMinimum;
111      this.uniqueItems = copyFrom.uniqueItems;
112      this.items = copyFrom.items == null ? null : copyFrom.items.copy();
113      this._default = copyFrom._default;
114      this._enum = newList(copyFrom._enum);
115      this.ref = copyFrom.ref;
116   }
117
118   /**
119    * Make a deep copy of this object.
120    *
121    * @return A deep copy of this object.
122    */
123   public Items copy() {
124      return new Items(this);
125   }
126
127
128   @Override /* SwaggerElement */
129   protected Items strict() {
130      super.strict();
131      return this;
132   }
133
134   /**
135    * Bean property getter:  <property>type</property>.
136    *
137    * <p>
138    * The internal type of the array.
139    *
140    * @return The property value, or <jk>null</jk> if it is not set.
141    */
142   public String getType() {
143      return type;
144   }
145
146   /**
147    * Bean property setter:  <property>type</property>.
148    *
149    * <p>
150    * The internal type of the array.
151    *
152    * <h5 class='section'>See Also:</h5>
153    * <ul class='doctree'>
154    *    <li class='extlink'>{@doc SwaggerDataTypes}
155    * </ul>
156    *
157    * @param value
158    *    The new value for this property.
159    *    <br>Valid values:
160    *    <ul>
161    *       <li><js>"string"</js>
162    *       <li><js>"number"</js>
163    *       <li><js>"integer"</js>
164    *       <li><js>"boolean"</js>
165    *       <li><js>"array"</js>
166    *    </ul>
167    *    <br>Property value is required.
168    * @return This object (for method chaining).
169    */
170   public Items setType(String value) {
171      if (isStrict() && ! contains(value, VALID_TYPES))
172         throw new RuntimeException(
173            "Invalid value passed in to setType(String).  Value='"+value+"', valid values="
174            + SimpleJsonSerializer.DEFAULT.toString(VALID_TYPES));
175      type = value;
176      return this;
177   }
178
179   /**
180    * Same as {@link #setType(String)}.
181    *
182    * @param value
183    *    The new value for this property.
184    *    <br>Non-String values will be converted to String using <code>toString()</code>.
185    *    <br>Valid values:
186    *    <ul>
187    *       <li><js>"string"</js>
188    *       <li><js>"number"</js>
189    *       <li><js>"integer"</js>
190    *       <li><js>"boolean"</js>
191    *       <li><js>"array"</js>
192    *    </ul>
193    *    <br>Can be <jk>null</jk> to unset the property.
194    * @return This object (for method chaining).
195    */
196   public Items type(Object value) {
197      return setType(toStringVal(value));
198   }
199
200   /**
201    * Bean property getter:  <property>format</property>.
202    *
203    * <p>
204    * The extending format for the previously mentioned <code>type</code>.
205    *
206    * <h5 class='section'>See Also:</h5>
207    * <ul>
208    *    <li class='extlink'>{@doc SwaggerDataTypeFormats}
209    * </ul>
210    *
211    * @return The property value, or <jk>null</jk> if it is not set.
212    */
213   public String getFormat() {
214      return format;
215   }
216
217   /**
218    * Bean property setter:  <property>format</property>.
219    *
220    * <p>
221    * The extending format for the previously mentioned <code>type</code>.
222    *
223    * <h5 class='section'>See Also:</h5>
224    * <ul>
225    *    <li class='extlink'>{@doc SwaggerDataTypeFormats}
226    * </ul>
227    *
228    * @param value
229    *    The new value for this property.
230    *    <br>Can be <jk>null</jk> to unset the property.
231    * @return This object (for method chaining).
232    */
233   public Items setFormat(String value) {
234      format = value;
235      return this;
236   }
237
238   /**
239    * Same as {@link #setFormat(String)}.
240    *
241    * @param value
242    *    The new value for this property.
243    *    <br>Non-String values will be converted to String using <code>toString()</code>.
244    *    <br>Can be <jk>null</jk> to unset the property.
245    * @return This object (for method chaining).
246    */
247   public Items format(Object value) {
248      return setFormat(toStringVal(value));
249   }
250
251   /**
252    * Bean property getter:  <property>items</property>.
253    *
254    * <p>
255    * Describes the type of items in the array.
256    *
257    * @return The property value, or <jk>null</jk> if it is not set.
258    */
259   public Items getItems() {
260      return items;
261   }
262
263   /**
264    * Bean property setter:  <property>items</property>.
265    *
266    * <p>
267    * Describes the type of items in the array.
268    *
269    * @param value
270    *    The new value for this property.
271    *    <br>Property value is required if <code>type</code> is <js>"array"</js>.
272    *    <br>Can be <jk>null</jk> to unset the property.
273    * @return This object (for method chaining).
274    */
275   public Items setItems(Items value) {
276      items = value;
277      return this;
278   }
279
280   /**
281    * Same as {@link #setItems(Items)}.
282    *
283    * @param value
284    *    The new value for this property.
285    *    <br>Property value is required if <code>type</code> is <js>"array"</js>.
286    *    <br>Valid types:
287    *    <ul>
288    *       <li>{@link Items}
289    *       <li><code>String</code> - JSON object representation of {@link Items}
290    *          <h5 class='figure'>Example:</h5>
291    *          <p class='bcode w800'>
292    *    items(<js>"{type:'type',format:'format',...}"</js>);
293    *          </p>
294    *    </ul>
295    *    <br>Can be <jk>null</jk> to unset the property.
296    * @return This object (for method chaining).
297    */
298   public Items items(Object value) {
299      return setItems(toType(value, Items.class));
300   }
301
302   /**
303    * Bean property getter:  <property>collectionFormat</property>.
304    *
305    * <p>
306    * Determines the format of the array if type array is used.
307    *
308    * @return The property value, or <jk>null</jk> if it is not set.
309    */
310   public String getCollectionFormat() {
311      return collectionFormat;
312   }
313
314   /**
315    * Bean property setter:  <property>collectionFormat</property>.
316    *
317    * <p>
318    * Determines the format of the array if type array is used.
319    *
320    * @param value
321    *    The new value for this property.
322    *    <br>Valid values:
323    *    <ul>
324    *       <li><js>"csv"</js> (default) - comma separated values <code>foo,bar</code>.
325    *       <li><js>"ssv"</js> - space separated values <code>foo bar</code>.
326    *       <li><js>"tsv"</js> - tab separated values <code>foo\tbar</code>.
327    *       <li><js>"pipes"</js> - pipe separated values <code>foo|bar</code>.
328    *    </ul>
329    *    <br>Can be <jk>null</jk> to unset the property.
330    * @return This object (for method chaining).
331    */
332   public Items setCollectionFormat(String value) {
333      if (isStrict() && ! contains(value, VALID_COLLECTION_FORMATS))
334         throw new FormattedRuntimeException(
335            "Invalid value passed in to setCollectionFormat(String).  Value=''{0}'', valid values={1}",
336            value, VALID_COLLECTION_FORMATS
337         );
338      collectionFormat = value;
339      return this;
340   }
341
342   /**
343    * Same as {@link #setCollectionFormat(String)}.
344    *
345    * @param value
346    *    The new value for this property.
347    *    <br>Non-String values will be converted to String using <code>toString()</code>.
348    *    <br>Valid values:
349    *    <ul>
350    *       <li><js>"csv"</js> (default) - comma separated values <code>foo,bar</code>.
351    *       <li><js>"ssv"</js> - space separated values <code>foo bar</code>.
352    *       <li><js>"tsv"</js> - tab separated values <code>foo\tbar</code>.
353    *       <li><js>"pipes"</js> - pipe separated values <code>foo|bar</code>.
354    *    </ul>
355    *    <br>Can be <jk>null</jk> to unset the property.
356    * @return This object (for method chaining).
357    */
358   public Items collectionFormat(Object value) {
359      return setCollectionFormat(toStringVal(value));
360   }
361
362   /**
363    * Bean property getter:  <property>default</property>.
364    *
365    * <p>
366    * Declares the value of the item that the server will use if none is provided.
367    *
368    * <h5 class='section'>Notes:</h5>
369    * <ul class='spaced-list'>
370    *    <li>
371    *       <js>"default"</js> has no meaning for required items.
372    *    <li>
373    *       Unlike JSON Schema this value MUST conform to the defined <code>type</code> for the data type.
374    * </ul>
375    *
376    * <h5 class='section'>See Also:</h5>
377    * <ul>
378    *    <li class='extlink'>{@doc JsonSchemaValidation}
379    * </ul>
380    *
381    * @return The property value, or <jk>null</jk> if it is not set.
382    */
383   public Object getDefault() {
384      return _default;
385   }
386
387   /**
388    * Bean property setter:  <property>default</property>.
389    *
390    * <p>
391    * Declares the value of the item that the server will use if none is provided.
392    *
393    * <h5 class='section'>Notes:</h5>
394    * <ul class='spaced-list'>
395    *    <li>
396    *       <js>"default"</js> has no meaning for required items.
397    *    <li>
398    *       Unlike JSON Schema this value MUST conform to the defined <code>type</code> for the data type.
399    * </ul>
400    *
401    * <h5 class='section'>See Also:</h5>
402    * <ul>
403    *    <li class='extlink'>{@doc JsonSchemaValidation}
404    * </ul>
405    *
406    * @param value
407    *    The new value for this property.
408    *    <br>Can be <jk>null</jk> to unset the property.
409    * @return This object (for method chaining).
410    */
411   public Items setDefault(Object value) {
412      _default = value;
413      return this;
414   }
415
416   /**
417    * Same as {@link #setDefault(Object)}.
418    *
419    * @param value
420    *    The new value for this property.
421    *    <br>Can be <jk>null</jk> to unset the property.
422    * @return This object (for method chaining).
423    */
424   public Items _default(Object value) {
425      return setDefault(value);
426   }
427
428   /**
429    * Bean property getter:  <property>maximum</property>.
430    *
431    * <h5 class='section'>See Also:</h5>
432    * <ul>
433    *    <li class='extlink'>{@doc JsonSchemaValidation}
434    * </ul>
435    *
436    * @return The property value, or <jk>null</jk> if it is not set.
437    */
438   public Number getMaximum() {
439      return maximum;
440   }
441
442   /**
443    * Bean property setter:  <property>maximum</property>.
444    *
445    * <h5 class='section'>See Also:</h5>
446    * <ul>
447    *    <li class='extlink'>{@doc JsonSchemaValidation}
448    * </ul>
449    *
450    * @param value
451    *    The new value for this property.
452    *    <br>Can be <jk>null</jk> to unset the property.
453    * @return This object (for method chaining).
454    */
455   public Items setMaximum(Number value) {
456      maximum = value;
457      return this;
458   }
459
460   /**
461    * Same as {@link #setMaximum(Number)}.
462    *
463    * @param value
464    *    The new value for this property.
465    *    <br>Non-Number values will be converted to Number using <code>toString()</code> then best number match.
466    *    <br>Can be <jk>null</jk> to unset the property.
467    * @return This object (for method chaining).
468    */
469   public Items maximum(Object value) {
470      return setMaximum(toNumber(value));
471   }
472
473   /**
474    * Bean property getter:  <property>exclusiveMaximum</property>.
475    *
476    * <h5 class='section'>See Also:</h5>
477    * <ul>
478    *    <li class='extlink'>{@doc JsonSchemaValidation}
479    * </ul>
480    *
481    * @return The property value, or <jk>null</jk> if it is not set.
482    */
483   public Boolean getExclusiveMaximum() {
484      return exclusiveMaximum;
485   }
486
487   /**
488    * Bean property setter:  <property>exclusiveMaximum</property>.
489    *
490    * <h5 class='section'>See Also:</h5>
491    * <ul>
492    *    <li class='extlink'>{@doc JsonSchemaValidation}
493    * </ul>
494    *
495    * @param value
496    *    The new value for this property.
497    *    <br>Can be <jk>null</jk> to unset the property.
498    * @return This object (for method chaining).
499    */
500   public Items setExclusiveMaximum(Boolean value) {
501      exclusiveMaximum = value;
502      return this;
503   }
504
505   /**
506    * Same as {@link #setExclusiveMaximum(Boolean)}.
507    *
508    * @param value
509    *    The new value for this property.
510    *    <br>Non-boolean values will be converted to boolean using <code>Boolean.<jsm>valueOf</jsm>(value.toString())</code>.
511    *    <br>Can be <jk>null</jk> to unset the property.
512    * @return This object (for method chaining).
513    */
514   public Items exclusiveMaximum(Object value) {
515      return setExclusiveMaximum(toBoolean(value));
516   }
517
518   /**
519    * Bean property getter:  <property>minimum</property>.
520    *
521    * <h5 class='section'>See Also:</h5>
522    * <ul>
523    *    <li class='extlink'>{@doc JsonSchemaValidation}
524    * </ul>
525    *
526    * @return The property value, or <jk>null</jk> if it is not set.
527    */
528   public Number getMinimum() {
529      return minimum;
530   }
531
532   /**
533    * Bean property setter:  <property>minimum</property>.
534    *
535    * <h5 class='section'>See Also:</h5>
536    * <ul>
537    *    <li class='extlink'>{@doc JsonSchemaValidation}
538    * </ul>
539    *
540    * @param value
541    *    The new value for this property.
542    *    <br>Can be <jk>null</jk> to unset the property.
543    * @return This object (for method chaining).
544    */
545   public Items setMinimum(Number value) {
546      minimum = value;
547      return this;
548   }
549
550   /**
551    * Same as {@link #setMinimum(Number)}.
552    *
553    * @param value
554    *    The new value for this property.
555    *    <br>Non-Number values will be converted to Number using <code>toString()</code> then best number match.
556    *    <br>Can be <jk>null</jk> to unset the property.
557    * @return This object (for method chaining).
558    */
559   public Items minimum(Object value) {
560      return setMinimum(toNumber(value));
561   }
562
563   /**
564    * Bean property getter:  <property>exclusiveMinimum</property>.
565    *
566    * <h5 class='section'>See Also:</h5>
567    * <ul>
568    *    <li class='extlink'>{@doc JsonSchemaValidation}
569    * </ul>
570    *
571    * @return The property value, or <jk>null</jk> if it is not set.
572    */
573   public Boolean getExclusiveMinimum() {
574      return exclusiveMinimum;
575   }
576
577   /**
578    * Bean property setter:  <property>exclusiveMinimum</property>.
579    *
580    * <h5 class='section'>See Also:</h5>
581    * <ul>
582    *    <li class='extlink'>{@doc JsonSchemaValidation}
583    * </ul>
584    *
585    * @param value
586    *    The new value for this property.
587    *    <br>Can be <jk>null</jk> to unset the property.
588    * @return This object (for method chaining).
589    */
590   public Items setExclusiveMinimum(Boolean value) {
591      exclusiveMinimum = value;
592      return this;
593   }
594
595   /**
596    * Same as {@link #setExclusiveMinimum(Boolean)}.
597    *
598    * @param value
599    *    The new value for this property.
600    *    <br>Non-boolean values will be converted to boolean using <code>Boolean.<jsm>valueOf</jsm>(value.toString())</code>.
601    *    <br>Can be <jk>null</jk> to unset the property.
602    * @return This object (for method chaining).
603    */
604   public Items exclusiveMinimum(Object value) {
605      return setExclusiveMinimum(toBoolean(value));
606   }
607
608   /**
609    * Bean property getter:  <property>maxLength</property>.
610    *
611    * <h5 class='section'>See Also:</h5>
612    * <ul>
613    *    <li class='extlink'>{@doc JsonSchemaValidation}
614    * </ul>
615    *
616    * @return The property value, or <jk>null</jk> if it is not set.
617    */
618   public Integer getMaxLength() {
619      return maxLength;
620   }
621
622   /**
623    * Bean property setter:  <property>maxLength</property>.
624    *
625    * <h5 class='section'>See Also:</h5>
626    * <ul>
627    *    <li class='extlink'>{@doc JsonSchemaValidation}
628    * </ul>
629    *
630    * @param value
631    *    The new value for this property.
632    *    <br>Can be <jk>null</jk> to unset the property.
633    * @return This object (for method chaining).
634    */
635   public Items setMaxLength(Integer value) {
636      maxLength = value;
637      return this;
638   }
639
640   /**
641    * Same as {@link #setMaxLength(Integer)}.
642    *
643    * @param value
644    *    The new value for this property.
645    *    <br>Non-Integer values will be converted to Integer using <code>Integer.<jsm>valueOf</jsm>(value.toString())</code>.
646    *    <br>Can be <jk>null</jk> to unset the property.
647    * @return This object (for method chaining).
648    */
649   public Items maxLength(Object value) {
650      return setMaxLength(toInteger(value));
651   }
652
653   /**
654    * Bean property getter:  <property>minLength</property>.
655    *
656    * <h5 class='section'>See Also:</h5>
657    * <ul>
658    *    <li class='extlink'>{@doc JsonSchemaValidation}
659    * </ul>
660    *
661    * @return The property value, or <jk>null</jk> if it is not set.
662    */
663   public Integer getMinLength() {
664      return minLength;
665   }
666
667   /**
668    * Bean property setter:  <property>minLength</property>.
669    *
670    * <h5 class='section'>See Also:</h5>
671    * <ul>
672    *    <li class='extlink'>{@doc JsonSchemaValidation}
673    * </ul>
674    *
675    * @param value
676    *    The new value for this property.
677    *    <br>Can be <jk>null</jk> to unset the property.
678    * @return This object (for method chaining).
679    */
680   public Items setMinLength(Integer value) {
681      minLength = value;
682      return this;
683   }
684
685   /**
686    * Same as {@link #setMinLength(Integer)}.
687    *
688    * @param value
689    *    The new value for this property.
690    *    <br>Non-Integer values will be converted to Integer using <code>Integer.<jsm>valueOf</jsm>(value.toString())</code>.
691    *    <br>Can be <jk>null</jk> to unset the property.
692    * @return This object (for method chaining).
693    */
694   public Items minLength(Object value) {
695      return setMinLength(toInteger(value));
696   }
697
698   /**
699    * Bean property getter:  <property>pattern</property>.
700    *
701    * <h5 class='section'>See Also:</h5>
702    * <ul>
703    *    <li class='extlink'>{@doc JsonSchemaValidation}
704    * </ul>
705    *
706    * @return The property value, or <jk>null</jk> if it is not set.
707    */
708   public String getPattern() {
709      return pattern;
710   }
711
712   /**
713    * Bean property setter:  <property>pattern</property>.
714    *
715    * <p>
716    * This string SHOULD be a valid regular expression.
717    *
718    * <h5 class='section'>See Also:</h5>
719    * <ul>
720    *    <li class='extlink'>{@doc JsonSchemaValidation}
721    * </ul>
722    *
723    * @param value
724    *    The new value for this property.
725    *    <br>Can be <jk>null</jk> to unset the property.
726    * @return This object (for method chaining).
727    */
728   public Items setPattern(String value) {
729      pattern = value;
730      return this;
731   }
732
733   /**
734    * Same as {@link #setPattern(String)}.
735    *
736    * @param value
737    *    The new value for this property.
738    *    <br>Non-String values will be converted to String using <code>toString()</code>.
739    *    <br>Can be <jk>null</jk> to unset the property.
740    * @return This object (for method chaining).
741    */
742   public Items pattern(Object value) {
743      return setPattern(toStringVal(value));
744   }
745
746   /**
747    * Bean property getter:  <property>maxItems</property>.
748    *
749    * <h5 class='section'>See Also:</h5>
750    * <ul>
751    *    <li class='extlink'>{@doc JsonSchemaValidation}
752    * </ul>
753    *
754    * @return The property value, or <jk>null</jk> if it is not set.
755    */
756   public Integer getMaxItems() {
757      return maxItems;
758   }
759
760   /**
761    * Bean property setter:  <property>maxItems</property>.
762    *
763    * <h5 class='section'>See Also:</h5>
764    * <ul>
765    *    <li class='extlink'>{@doc JsonSchemaValidation}
766    * </ul>
767    *
768    * @param value
769    *    The new value for this property.
770    *    <br>Can be <jk>null</jk> to unset the property.
771    * @return This object (for method chaining).
772    */
773   public Items setMaxItems(Integer value) {
774      maxItems = value;
775      return this;
776   }
777
778   /**
779    * Same as {@link #setMaxItems(Integer)}.
780    *
781    * @param value
782    *    The new value for this property.
783    *    <br>Non-Integer values will be converted to Integer using <code>Integer.<jsm>valueOf</jsm>(value.toString())</code>.
784    *    <br>Can be <jk>null</jk> to unset the property.
785    * @return This object (for method chaining).
786    */
787   public Items maxItems(Object value) {
788      return setMaxItems(toInteger(value));
789   }
790
791   /**
792    * Bean property getter:  <property>minItems</property>.
793    *
794    * <h5 class='section'>See Also:</h5>
795    * <ul>
796    *    <li class='extlink'>{@doc JsonSchemaValidation}
797    * </ul>
798    *
799    * @return The property value, or <jk>null</jk> if it is not set.
800    */
801   public Integer getMinItems() {
802      return minItems;
803   }
804
805   /**
806    * Bean property setter:  <property>minItems</property>.
807    *
808    * <h5 class='section'>See Also:</h5>
809    * <ul>
810    *    <li class='extlink'>{@doc JsonSchemaValidation}
811    * </ul>
812    *
813    * @param value
814    *    The new value for this property.
815    *    <br>Can be <jk>null</jk> to unset the property.
816    * @return This object (for method chaining).
817    */
818   public Items setMinItems(Integer value) {
819      minItems = value;
820      return this;
821   }
822
823   /**
824    * Same as {@link #setMinItems(Integer)}.
825    *
826    * @param value
827    *    The new value for this property.
828    *    <br>Non-Integer values will be converted to Integer using <code>Integer.<jsm>valueOf</jsm>(value.toString())</code>.
829    *    <br>Can be <jk>null</jk> to unset the property.
830    * @return This object (for method chaining).
831    */
832   public Items minItems(Object value) {
833      return setMinItems(toInteger(value));
834   }
835
836   /**
837    * Bean property getter:  <property>uniqueItems</property>.
838    *
839    * <h5 class='section'>See Also:</h5>
840    * <ul>
841    *    <li class='extlink'>{@doc JsonSchemaValidation}
842    * </ul>
843    *
844    * @return The property value, or <jk>null</jk> if it is not set.
845    */
846   public Boolean getUniqueItems() {
847      return uniqueItems;
848   }
849
850   /**
851    * Bean property setter:  <property>uniqueItems</property>.
852    *
853    * <h5 class='section'>See Also:</h5>
854    * <ul>
855    *    <li class='extlink'>{@doc JsonSchemaValidation}
856    * </ul>
857    *
858    * @param value
859    *    The new value for this property.
860    *    <br>Can be <jk>null</jk> to unset the property.
861    * @return This object (for method chaining).
862    */
863   public Items setUniqueItems(Boolean value) {
864      uniqueItems = value;
865      return this;
866   }
867
868   /**
869    * Same as {@link #setUniqueItems(Boolean)}.
870    *
871    * @param value
872    *    The new value for this property.
873    *    <br>Non-boolean values will be converted to boolean using <code>Boolean.<jsm>valueOf</jsm>(value.toString())</code>.
874    *    <br>Can be <jk>null</jk> to unset the property.
875    * @return This object (for method chaining).
876    */
877   public Items uniqueItems(Object value) {
878      return setUniqueItems(toBoolean(value));
879   }
880
881   /**
882    * Bean property getter:  <property>enum</property>.
883    *
884    * <h5 class='section'>See Also:</h5>
885    * <ul>
886    *    <li class='extlink'>{@doc JsonSchemaValidation}
887    * </ul>
888    *
889    * @return The property value, or <jk>null</jk> if it is not set.
890    */
891   public List<Object> getEnum() {
892      return _enum;
893   }
894
895   /**
896    * Bean property setter:  <property>enum</property>.
897    *
898    * <h5 class='section'>See Also:</h5>
899    * <ul>
900    *    <li class='extlink'>{@doc JsonSchemaValidation}
901    * </ul>
902    *
903    * @param value
904    *    The new value for this property.
905    *    <br>Can be <jk>null</jk> to unset the property.
906    * @return This object (for method chaining).
907    */
908   public Items setEnum(Collection<Object> value) {
909      _enum = newList(value);
910      return this;
911   }
912
913   /**
914    * Adds one or more values to the <property>enum</property> property.
915    *
916    * @param values
917    *    The values to add to this property.
918    *    <br>Ignored if <jk>null</jk>.
919    * @return This object (for method chaining).
920    */
921   public Items addEnum(Collection<Object> values) {
922      _enum = addToList(_enum, values);
923      return this;
924   }
925
926   /**
927    * Adds one or more values to the <property>enum</property> property.
928    *
929    * @param values
930    *    The values to add to this property.
931    *    <br>Valid types:
932    *    <ul>
933    *       <li><code>Object</code>
934    *       <li><code>Collection&lt;Object&gt;</code>
935    *       <li><code>String</code> - JSON array representation of <code>Collection&lt;Object&gt;</code>
936    *          <h5 class='figure'>Example:</h5>
937    *          <p class='bcode w800'>
938    *    _enum(<js>"['foo','bar']"</js>);
939    *          </p>
940    *       <li><code>String</code> - Individual values
941    *          <h5 class='figure'>Example:</h5>
942    *          <p class='bcode w800'>
943    *    _enum(<js>"foo"</js>, <js>"bar"</js>);
944    *          </p>
945    *    </ul>
946    *    <br>Ignored if <jk>null</jk>.
947    * @return This object (for method chaining).
948    */
949   public Items _enum(Object...values) {
950      _enum = addToList(_enum, values, Object.class);
951      return this;
952   }
953
954   /**
955    * Bean property getter:  <property>multipleOf</property>.
956    *
957    * <h5 class='section'>See Also:</h5>
958    * <ul>
959    *    <li class='extlink'>{@doc JsonSchemaValidation}
960    * </ul>
961    *
962    * @return The property value, or <jk>null</jk> if it is not set.
963    */
964   public Number getMultipleOf() {
965      return multipleOf;
966   }
967
968   /**
969    * Bean property setter:  <property>multipleOf</property>.
970    *
971    * <h5 class='section'>See Also:</h5>
972    * <ul>
973    *    <li class='extlink'>{@doc JsonSchemaValidation}
974    * </ul>
975    *
976    * @param value
977    *    The new value for this property.
978    *    <br>Can be <jk>null</jk> to unset the property.
979    * @return This object (for method chaining).
980    */
981   public Items setMultipleOf(Number value) {
982      multipleOf = value;
983      return this;
984   }
985
986   /**
987    * Same as {@link #setMultipleOf(Number)}.
988    *
989    * @param value
990    *    The new value for this property.
991    *    <br>Non-Number values will be converted to Number using <code>toString()</code> then best number match.
992    *    <br>Can be <jk>null</jk> to unset the property.
993    * @return This object (for method chaining).
994    */
995   public Items multipleOf(Object value) {
996      return setMultipleOf(toNumber(value));
997   }
998
999   /**
1000    * Bean property getter:  <property>$ref</property>.
1001    *
1002    * @return The property value, or <jk>null</jk> if it is not set.
1003    */
1004   @BeanProperty("$ref")
1005   public String getRef() {
1006      return ref;
1007   }
1008
1009   /**
1010    * Returns <jk>true</jk> if this object has a <js>"$ref"</js> attribute.
1011    *
1012    * @return <jk>true</jk> if this object has a <js>"$ref"</js> attribute.
1013    */
1014   public boolean hasRef() {
1015      return ref != null;
1016   }
1017
1018   /**
1019    * Bean property setter:  <property>$ref</property>.
1020    *
1021    * @param value
1022    *    The new value for this property.
1023    *    <br>Can be <jk>null</jk> to unset the property.
1024    * @return This object (for method chaining).
1025    */
1026   @BeanProperty("$ref")
1027   public Items setRef(Object value) {
1028      ref = StringUtils.asString(value);
1029      return this;
1030   }
1031
1032   /**
1033    * Same as {@link #setRef(Object)}.
1034    *
1035    * @param value
1036    *    The new value for this property.
1037    *    <br>Can be <jk>null</jk> to unset the property.
1038    * @return This object (for method chaining).
1039    */
1040   public Items ref(Object value) {
1041      return setRef(value);
1042   }
1043
1044   @Override /* SwaggerElement */
1045   public <T> T get(String property, Class<T> type) {
1046      if (property == null)
1047         return null;
1048      switch (property) {
1049         case "type": return toType(getType(), type);
1050         case "format": return toType(getFormat(), type);
1051         case "items": return toType(getItems(), type);
1052         case "collectionFormat": return toType(getCollectionFormat(), type);
1053         case "default": return toType(getDefault(), type);
1054         case "maximum": return toType(getMaximum(), type);
1055         case "exclusiveMaximum": return toType(getExclusiveMaximum(), type);
1056         case "minimum": return toType(getMinimum(), type);
1057         case "exclusiveMinimum": return toType(getExclusiveMinimum(), type);
1058         case "maxLength": return toType(getMaxLength(), type);
1059         case "minLength": return toType(getMinLength(), type);
1060         case "pattern": return toType(getPattern(), type);
1061         case "maxItems": return toType(getMaxItems(), type);
1062         case "minItems": return toType(getMinItems(), type);
1063         case "uniqueItems": return toType(getUniqueItems(), type);
1064         case "enum": return toType(getEnum(), type);
1065         case "multipleOf": return toType(getMultipleOf(), type);
1066         case "$ref": return toType(getRef(), type);
1067         default: return super.get(property, type);
1068      }
1069   }
1070
1071   @Override /* SwaggerElement */
1072   public Items set(String property, Object value) {
1073      if (property == null)
1074         return this;
1075      switch (property) {
1076         case "type": return type(value);
1077         case "format": return format(value);
1078         case "items": return items(value);
1079         case "collectionFormat": return collectionFormat(value);
1080         case "default": return _default(value);
1081         case "maximum": return maximum(value);
1082         case "exclusiveMaximum": return exclusiveMaximum(value);
1083         case "minimum": return minimum(value);
1084         case "exclusiveMinimum": return exclusiveMinimum(value);
1085         case "maxLength": return maxLength(value);
1086         case "minLength": return minLength(value);
1087         case "pattern": return pattern(value);
1088         case "maxItems": return maxItems(value);
1089         case "minItems": return minItems(value);
1090         case "uniqueItems": return uniqueItems(value);
1091         case "enum": return setEnum(null)._enum(value);
1092         case "multipleOf": return multipleOf(value);
1093         case "$ref": return ref(value);
1094         default:
1095            super.set(property, value);
1096            return this;
1097      }
1098   }
1099
1100   @Override /* SwaggerElement */
1101   public Set<String> keySet() {
1102      ASet<String> s = new ASet<String>()
1103         .appendIf(type != null, "type")
1104         .appendIf(format != null, "format")
1105         .appendIf(items != null, "items")
1106         .appendIf(collectionFormat != null, "collectionFormat")
1107         .appendIf(_default != null, "default")
1108         .appendIf(maximum != null, "maximum")
1109         .appendIf(exclusiveMaximum != null, "exclusiveMaximum")
1110         .appendIf(minimum != null, "minimum")
1111         .appendIf(exclusiveMinimum != null, "exclusiveMinimum")
1112         .appendIf(maxLength != null, "maxLength")
1113         .appendIf(minLength != null, "minLength")
1114         .appendIf(pattern != null, "pattern")
1115         .appendIf(maxItems != null, "maxItems")
1116         .appendIf(minItems != null, "minItems")
1117         .appendIf(uniqueItems != null, "uniqueItems")
1118         .appendIf(_enum != null, "enum")
1119         .appendIf(multipleOf != null, "multipleOf")
1120         .appendIf(ref != null, "$ref");
1121      return new MultiSet<>(s, super.keySet());
1122   }
1123
1124   /**
1125    * Resolves any <js>"$ref"</js> attributes in this element.
1126    *
1127    * @param swagger The swagger document containing the definitions.
1128    * @param refStack Keeps track of previously-visited references so that we don't cause recursive loops.
1129    * @param maxDepth
1130    *    The maximum depth to resolve references.
1131    *    <br>After that level is reached, <code>$ref</code> references will be left alone.
1132    *    <br>Useful if you have very complex models and you don't want your swagger page to be overly-complex.
1133    * @return
1134    *    This object with references resolved.
1135    *    <br>May or may not be the same object.
1136    */
1137   public Items resolveRefs(Swagger swagger, Deque<String> refStack, int maxDepth) {
1138
1139      if (ref != null) {
1140         if (refStack.contains(ref) || refStack.size() >= maxDepth)
1141            return this;
1142         refStack.addLast(ref);
1143         Items r = swagger.findRef(ref, Items.class).resolveRefs(swagger, refStack, maxDepth);
1144         refStack.removeLast();
1145         return r;
1146      }
1147
1148      set("properties", resolveRefs(get("properties"), swagger, refStack, maxDepth));
1149
1150      if (items != null)
1151         items = items.resolveRefs(swagger, refStack, maxDepth);
1152
1153      set("example", null);
1154
1155      return this;
1156   }
1157
1158   /* Resolve references in extra attributes */
1159   private Object resolveRefs(Object o, Swagger swagger, Deque<String> refStack, int maxDepth) {
1160      if (o instanceof ObjectMap) {
1161         ObjectMap om = (ObjectMap)o;
1162         Object ref = om.get("$ref");
1163         if (ref instanceof CharSequence) {
1164            String sref = ref.toString();
1165            if (refStack.contains(sref) || refStack.size() >= maxDepth)
1166               return o;
1167            refStack.addLast(sref);
1168            Object o2 = swagger.findRef(sref, Object.class);
1169            o2 = resolveRefs(o2, swagger, refStack, maxDepth);
1170            refStack.removeLast();
1171            return o2;
1172         }
1173         for (Map.Entry<String,Object> e : om.entrySet())
1174            e.setValue(resolveRefs(e.getValue(), swagger, refStack, maxDepth));
1175      }
1176      if (o instanceof ObjectList)
1177         for (ListIterator<Object> li = ((ObjectList)o).listIterator(); li.hasNext();)
1178            li.set(resolveRefs(li.next(), swagger, refStack, maxDepth));
1179      return o;
1180   }
1181}