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