001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.bean.swagger;
018
019import static org.apache.juneau.common.utils.Utils.*;
020import static org.apache.juneau.internal.CollectionUtils.*;
021import static org.apache.juneau.internal.ConverterUtils.*;
022
023import java.util.*;
024
025import org.apache.juneau.*;
026import org.apache.juneau.annotation.*;
027import org.apache.juneau.common.utils.*;
028import org.apache.juneau.internal.*;
029import org.apache.juneau.marshaller.*;
030
031/**
032 * A limited subset of JSON-Schema's items object.
033 *
034 * <p>
035 * The Items Object is a limited subset of JSON-Schema's items object for Swagger 2.0. It is used by parameter 
036 * definitions that are not located in "body" to describe the type of items in an array. This is particularly useful 
037 * for query parameters, path parameters, and header parameters that accept arrays.
038 *
039 * <h5 class='section'>Swagger Specification:</h5>
040 * <p>
041 * The Items Object supports the following fields from JSON Schema:
042 * <ul class='spaced-list'>
043 *    <li><c>type</c> (string, REQUIRED) - The data type. Values: <js>"string"</js>, <js>"number"</js>, <js>"integer"</js>, <js>"boolean"</js>, <js>"array"</js>
044 *    <li><c>format</c> (string) - The format modifier (e.g., <js>"int32"</js>, <js>"int64"</js>, <js>"float"</js>, <js>"double"</js>, <js>"date"</js>, <js>"date-time"</js>)
045 *    <li><c>items</c> ({@link Items}) - Required if type is <js>"array"</js>. Describes the type of items in the array
046 *    <li><c>collectionFormat</c> (string) - How multiple values are formatted. Values: <js>"csv"</js>, <js>"ssv"</js>, <js>"tsv"</js>, <js>"pipes"</js>, <js>"multi"</js>
047 *    <li><c>default</c> (any) - The default value
048 *    <li><c>maximum</c> (number), <c>exclusiveMaximum</c> (boolean), <c>minimum</c> (number), <c>exclusiveMinimum</c> (boolean) - Numeric constraints
049 *    <li><c>maxLength</c> (integer), <c>minLength</c> (integer), <c>pattern</c> (string) - String constraints
050 *    <li><c>maxItems</c> (integer), <c>minItems</c> (integer), <c>uniqueItems</c> (boolean) - Array constraints
051 *    <li><c>enum</c> (array) - Possible values for this item
052 *    <li><c>multipleOf</c> (number) - Must be a multiple of this value
053 * </ul>
054 *
055 * <h5 class='section'>Example:</h5>
056 * <p class='bjava'>
057 *    <jc>// Construct using SwaggerBuilder.</jc>
058 *    Items <jv>items</jv> = <jsm>items</jsm>(<js>"string"</js>).minLength(2);
059 *
060 *    <jc>// Serialize using JsonSerializer.</jc>
061 *    String <jv>json</jv> = Json.<jsm>from</jsm>(<jv>items</jv>);
062 *
063 *    <jc>// Or just use toString() which does the same as above.</jc>
064 *    <jv>json</jv> = <jv>items</jv>.toString();
065 * </p>
066 * <p class='bjson'>
067 *    <jc>// Output</jc>
068 *    {
069 *       <js>"type"</js>: <js>"string"</js>,
070 *       <js>"minLength"</js>: 2
071 *    }
072 * </p>
073 *
074 * <h5 class='section'>See Also:</h5><ul>
075 *    <li class='link'><a class="doclink" href="https://swagger.io/specification/v2/#items-object">Swagger 2.0 Specification &gt; Items Object</a>
076 *    <li class='link'><a class="doclink" href="https://swagger.io/docs/specification/2-0/describing-parameters/">Swagger Describing Parameters</a>
077 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauBeanSwagger2">juneau-bean-swagger-v2</a>
078 * </ul>
079 */
080public class Items extends SwaggerElement {
081
082   private static final String[] VALID_TYPES = {"string", "number", "integer", "boolean", "array"};
083   private static final String[] VALID_COLLECTION_FORMATS = {"csv","ssv","tsv","pipes","multi"};
084
085   private String
086      type,
087      format,
088      collectionFormat,
089      pattern,
090      ref;
091   private Number
092      maximum,
093      minimum,
094      multipleOf;
095   private Integer
096      maxLength,
097      minLength,
098      maxItems,
099      minItems;
100   private Boolean
101      exclusiveMaximum,
102      exclusiveMinimum,
103      uniqueItems;
104   private Items items;  // NOSONAR - Intentional naming.
105   private Object _default;  // NOSONAR - Intentional naming.
106   private Set<Object> _enum;  // NOSONAR - Intentional naming.
107
108   /**
109    * Default constructor.
110    */
111   public Items() {}
112
113   /**
114    * Copy constructor.
115    *
116    * @param copyFrom The object to copy.
117    */
118   public Items(Items copyFrom) {
119      super(copyFrom);
120
121      this.collectionFormat = copyFrom.collectionFormat;
122      this._default = copyFrom._default;
123      this._enum = copyOf(copyFrom._enum);
124      this.exclusiveMaximum = copyFrom.exclusiveMaximum;
125      this.exclusiveMinimum = copyFrom.exclusiveMinimum;
126      this.format = copyFrom.format;
127      this.items = copyFrom.items == null ? null : copyFrom.items.copy();
128      this.maximum = copyFrom.maximum;
129      this.maxItems = copyFrom.maxItems;
130      this.maxLength = copyFrom.maxLength;
131      this.minimum = copyFrom.minimum;
132      this.minItems = copyFrom.minItems;
133      this.minLength = copyFrom.minLength;
134      this.multipleOf = copyFrom.multipleOf;
135      this.pattern = copyFrom.pattern;
136      this.ref = copyFrom.ref;
137      this.type = copyFrom.type;
138      this.uniqueItems = copyFrom.uniqueItems;
139   }
140
141   /**
142    * Make a deep copy of this object.
143    *
144    * @return A deep copy of this object.
145    */
146   public Items copy() {
147      return new Items(this);
148   }
149
150   @Override /* Overridden from SwaggerElement */
151   public Items strict() {
152      super.strict();
153      return this;
154   }
155
156   /**
157    * Sets strict mode on this bean.
158    *
159    * @param value
160    *    The new value for this property.
161    *    <br>Non-boolean values will be converted to boolean using <code>Boolean.<jsm>valueOf</jsm>(value.toString())</code>.
162    *    <br>Can be <jk>null</jk> (interpreted as <jk>false</jk>).
163    * @return This object.
164    */
165   @Override
166   public Items strict(Object value) {
167      super.strict(value);
168      return this;
169   }
170
171   //-----------------------------------------------------------------------------------------------------------------
172   // Properties
173   //-----------------------------------------------------------------------------------------------------------------
174
175   /**
176    * Bean property getter:  <property>collectionFormat</property>.
177    *
178    * <p>
179    * Determines the format of the array if type array is used.
180    *
181    * @return The property value, or <jk>null</jk> if it is not set.
182    */
183   public String getCollectionFormat() {
184      return collectionFormat;
185   }
186
187   /**
188    * Bean property setter:  <property>collectionFormat</property>.
189    *
190    * <p>
191    * Determines the format of the array if type array is used.
192    *
193    * @param value
194    *    The new value for this property.
195    *    <br>Valid values:
196    *    <ul>
197    *       <li><js>"csv"</js> (default) - comma separated values <c>foo,bar</c>.
198    *       <li><js>"ssv"</js> - space separated values <c>foo bar</c>.
199    *       <li><js>"tsv"</js> - tab separated values <c>foo\tbar</c>.
200    *       <li><js>"pipes"</js> - pipe separated values <c>foo|bar</c>.
201    *    </ul>
202    *    <br>Can be <jk>null</jk> to unset the property.
203    * @return This object.
204    */
205   public Items setCollectionFormat(String value) {
206      if (isStrict() && ! ArrayUtils.contains(value, VALID_COLLECTION_FORMATS))
207         throw new BasicRuntimeException(
208            "Invalid value passed in to setCollectionFormat(String).  Value=''{0}'', valid values={1}",
209            value, Json5.of(VALID_COLLECTION_FORMATS)
210         );
211      collectionFormat = value;
212      return this;
213   }
214
215   /**
216    * Bean property getter:  <property>default</property>.
217    *
218    * <p>
219    * Declares the value of the item that the server will use if none is provided.
220    *
221    * <h5 class='section'>Notes:</h5><ul>
222    *    <li class='note'>
223    *       <js>"default"</js> has no meaning for required items.
224    *    <li class='note'>
225    *       Unlike JSON Schema this value MUST conform to the defined <c>type</c> for the data type.
226    * </ul>
227    *
228    * @return The property value, or <jk>null</jk> if it is not set.
229    */
230   public Object getDefault() {
231      return _default;
232   }
233
234   /**
235    * Bean property setter:  <property>default</property>.
236    *
237    * <p>
238    * Declares the value of the item that the server will use if none is provided.
239    *
240    * <h5 class='section'>Notes:</h5><ul>
241    *    <li class='note'>
242    *       <js>"default"</js> has no meaning for required items.
243    *    <li class='note'>
244    *       Unlike JSON Schema this value MUST conform to the defined <c>type</c> for the data type.
245    * </ul>
246    *
247    * @param value
248    *    The new value for this property.
249    *    <br>Can be <jk>null</jk> to unset the property.
250    * @return This object.
251    */
252   public Items setDefault(Object value) {
253      _default = value;
254      return this;
255   }
256
257   /**
258    * Bean property getter:  <property>enum</property>.
259    *
260    * @return The property value, or <jk>null</jk> if it is not set.
261    */
262   public Set<Object> getEnum() {
263      return _enum;
264   }
265
266   /**
267    * Bean property setter:  <property>enum</property>.
268    *
269    * @param value
270    *    The new value for this property.
271    *    <br>Can be <jk>null</jk> to unset the property.
272    * @return This object.
273    */
274   public Items setEnum(Collection<Object> value) {
275      _enum = setFrom(value);
276      return this;
277   }
278
279   /**
280    * Bean property setter:  <property>enum</property>.
281    *
282    * @param value
283    *    The new value for this property.
284    *    <br>Can be <jk>null</jk> to unset the property.
285    * @return This object.
286    */
287   public Items setEnum(Object...value) {
288      return setEnum(Arrays.asList(value));
289   }
290
291   /**
292    * Bean property fluent setter:  <property>enum</property>.
293    *
294    * @param value
295    *    The new value for this property.
296    *    <br>String values can be JSON arrays.
297    * @return This object.
298    */
299   public Items addEnum(Object...value) {
300      setEnum(setBuilder(_enum).sparse().add(value).build());
301      return this;
302   }
303
304   /**
305    * Bean property getter:  <property>exclusiveMaximum</property>.
306    *
307    * @return The property value, or <jk>null</jk> if it is not set.
308    */
309   public Boolean getExclusiveMaximum() {
310      return exclusiveMaximum;
311   }
312
313   /**
314    * Bean property setter:  <property>exclusiveMaximum</property>.
315    *
316    * @param value
317    *    The new value for this property.
318    *    <br>Can be <jk>null</jk> to unset the property.
319    * @return This object.
320    */
321   public Items setExclusiveMaximum(Boolean value) {
322      exclusiveMaximum = value;
323      return this;
324   }
325
326   /**
327    * Bean property getter:  <property>exclusiveMinimum</property>.
328    *
329    * @return The property value, or <jk>null</jk> if it is not set.
330    */
331   public Boolean getExclusiveMinimum() {
332      return exclusiveMinimum;
333   }
334
335   /**
336    * Bean property setter:  <property>exclusiveMinimum</property>.
337    *
338    * @param value
339    *    The new value for this property.
340    *    <br>Can be <jk>null</jk> to unset the property.
341    * @return This object.
342    */
343   public Items setExclusiveMinimum(Boolean value) {
344      exclusiveMinimum = value;
345      return this;
346   }
347
348   /**
349    * Bean property getter:  <property>format</property>.
350    *
351    * <p>
352    * The extending format for the previously mentioned <c>type</c>.
353    *
354    * @return The property value, or <jk>null</jk> if it is not set.
355    */
356   public String getFormat() {
357      return format;
358   }
359
360   /**
361    * Bean property setter:  <property>format</property>.
362    *
363    * <p>
364    * The extending format for the previously mentioned <c>type</c>.
365    *
366    * @param value
367    *    The new value for this property.
368    *    <br>Can be <jk>null</jk> to unset the property.
369    * @return This object.
370    */
371   public Items setFormat(String value) {
372      format = value;
373      return this;
374   }
375
376   /**
377    * Bean property getter:  <property>items</property>.
378    *
379    * <p>
380    * Describes the type of items in the array.
381    *
382    * @return The property value, or <jk>null</jk> if it is not set.
383    */
384   public Items getItems() {
385      return items;
386   }
387
388   /**
389    * Bean property setter:  <property>items</property>.
390    *
391    * <p>
392    * Describes the type of items in the array.
393    *
394    * @param value
395    *    The new value for this property.
396    *    <br>Property value is required if <c>type</c> is <js>"array"</js>.
397    *    <br>Can be <jk>null</jk> to unset the property.
398    * @return This object.
399    */
400   public Items setItems(Items value) {
401      items = value;
402      return this;
403   }
404
405   /**
406    * Bean property getter:  <property>maximum</property>.
407    *
408    * @return The property value, or <jk>null</jk> if it is not set.
409    */
410   public Number getMaximum() {
411      return maximum;
412   }
413
414   /**
415    * Bean property setter:  <property>maximum</property>.
416    *
417    * @param value
418    *    The new value for this property.
419    *    <br>Can be <jk>null</jk> to unset the property.
420    * @return This object.
421    */
422   public Items setMaximum(Number value) {
423      maximum = value;
424      return this;
425   }
426
427   /**
428    * Bean property getter:  <property>maxItems</property>.
429    *
430    * @return The property value, or <jk>null</jk> if it is not set.
431    */
432   public Integer getMaxItems() {
433      return maxItems;
434   }
435
436   /**
437    * Bean property setter:  <property>maxItems</property>.
438    *
439    * @param value
440    *    The new value for this property.
441    *    <br>Can be <jk>null</jk> to unset the property.
442    * @return This object.
443    */
444   public Items setMaxItems(Integer value) {
445      maxItems = value;
446      return this;
447   }
448
449   //-----------------------------------------------------------------------------------------------------------------
450   // maxLength
451   //-----------------------------------------------------------------------------------------------------------------
452
453   /**
454    * Bean property getter:  <property>maxLength</property>.
455    *
456    * @return The property value, or <jk>null</jk> if it is not set.
457    */
458   public Integer getMaxLength() {
459      return maxLength;
460   }
461
462   /**
463    * Bean property setter:  <property>maxLength</property>.
464    *
465    * @param value
466    *    The new value for this property.
467    *    <br>Can be <jk>null</jk> to unset the property.
468    * @return This object.
469    */
470   public Items setMaxLength(Integer value) {
471      maxLength = value;
472      return this;
473   }
474
475   /**
476    * Bean property getter:  <property>minimum</property>.
477    *
478    * @return The property value, or <jk>null</jk> if it is not set.
479    */
480   public Number getMinimum() {
481      return minimum;
482   }
483
484   /**
485    * Bean property setter:  <property>minimum</property>.
486    *
487    * @param value
488    *    The new value for this property.
489    *    <br>Can be <jk>null</jk> to unset the property.
490    * @return This object.
491    */
492   public Items setMinimum(Number value) {
493      minimum = value;
494      return this;
495   }
496
497   /**
498    * Bean property getter:  <property>minItems</property>.
499    *
500    * @return The property value, or <jk>null</jk> if it is not set.
501    */
502   public Integer getMinItems() {
503      return minItems;
504   }
505
506   /**
507    * Bean property setter:  <property>minItems</property>.
508    *
509    * @param value
510    *    The new value for this property.
511    *    <br>Can be <jk>null</jk> to unset the property.
512    * @return This object.
513    */
514   public Items setMinItems(Integer value) {
515      minItems = value;
516      return this;
517   }
518
519   /**
520    * Bean property getter:  <property>minLength</property>.
521    *
522    * @return The property value, or <jk>null</jk> if it is not set.
523    */
524   public Integer getMinLength() {
525      return minLength;
526   }
527
528   /**
529    * Bean property setter:  <property>minLength</property>.
530    *
531    * @param value
532    *    The new value for this property.
533    *    <br>Can be <jk>null</jk> to unset the property.
534    * @return This object.
535    */
536   public Items setMinLength(Integer value) {
537      minLength = value;
538      return this;
539   }
540
541   /**
542    * Bean property getter:  <property>multipleOf</property>.
543    *
544    * @return The property value, or <jk>null</jk> if it is not set.
545    */
546   public Number getMultipleOf() {
547      return multipleOf;
548   }
549
550   /**
551    * Bean property setter:  <property>multipleOf</property>.
552    *
553    * @param value
554    *    The new value for this property.
555    *    <br>Can be <jk>null</jk> to unset the property.
556    * @return This object.
557    */
558   public Items setMultipleOf(Number value) {
559      multipleOf = value;
560      return this;
561   }
562
563   /**
564    * Bean property getter:  <property>pattern</property>.
565    *
566    * @return The property value, or <jk>null</jk> if it is not set.
567    */
568   public String getPattern() {
569      return pattern;
570   }
571
572   /**
573    * Bean property setter:  <property>pattern</property>.
574    *
575    * @param value
576    *    The new value for this property.
577    *    <br>This string SHOULD be a valid regular expression.
578    *    <br>Can be <jk>null</jk> to unset the property.
579    * @return This object.
580    */
581   public Items setPattern(String value) {
582      pattern = value;
583      return this;
584   }
585
586   /**
587    * Bean property getter:  <property>$ref</property>.
588    *
589    * @return The property value, or <jk>null</jk> if it is not set.
590    */
591   @Beanp("$ref")
592   public String getRef() {
593      return ref;
594   }
595
596   /**
597    * Bean property setter:  <property>$ref</property>.
598    *
599    * @param value
600    *    The new value for this property.
601    *    <br>Can be <jk>null</jk> to unset the property.
602    * @return This object.
603    */
604   @Beanp("$ref")
605   public Items setRef(String value) {
606      ref = value;
607      return this;
608   }
609
610   /**
611    * Bean property getter:  <property>type</property>.
612    *
613    * <p>
614    * The internal type of the array.
615    *
616    * @return The property value, or <jk>null</jk> if it is not set.
617    */
618   public String getType() {
619      return type;
620   }
621
622   /**
623    * Bean property setter:  <property>type</property>.
624    *
625    * <p>
626    * The internal type of the array.
627    *
628    * @param value
629    *    The new value for this property.
630    *    <br>Valid values:
631    *    <ul>
632    *       <li><js>"string"</js>
633    *       <li><js>"number"</js>
634    *       <li><js>"integer"</js>
635    *       <li><js>"boolean"</js>
636    *       <li><js>"array"</js>
637    *    </ul>
638    *    <br>Property value is required.
639    *    <br>Can be <jk>null</jk> to unset the property.
640    * @return This object.
641    */
642   public Items setType(String value) {
643      if (isStrict() && ! ArrayUtils.contains(value, VALID_TYPES))
644         throw new BasicRuntimeException("Invalid value passed in to setType(String).  Value=''{0}'', valid values={1}", value, Json5.of(VALID_TYPES));
645      type = value;
646      return this;
647   }
648
649   /**
650    * Bean property getter:  <property>uniqueItems</property>.
651    *
652    * @return The property value, or <jk>null</jk> if it is not set.
653    */
654   public Boolean getUniqueItems() {
655      return uniqueItems;
656   }
657
658   /**
659    * Bean property setter:  <property>uniqueItems</property>.
660    *
661    * @param value
662    *    The new value for this property.
663    *    <br>Can be <jk>null</jk> to unset the property.
664    * @return This object.
665    */
666   public Items setUniqueItems(Boolean value) {
667      uniqueItems = value;
668      return this;
669   }
670
671   @Override /* Overridden from SwaggerElement */
672   public <T> T get(String property, Class<T> type) {
673      assertArgNotNull("property", property);
674      return switch (property) {
675         case "collectionFormat" -> toType(getCollectionFormat(), type);
676         case "default" -> toType(getDefault(), type);
677         case "enum" -> toType(getEnum(), type);
678         case "exclusiveMaximum" -> toType(getExclusiveMaximum(), type);
679         case "exclusiveMinimum" -> toType(getExclusiveMinimum(), type);
680         case "format" -> toType(getFormat(), type);
681         case "items" -> toType(getItems(), type);
682         case "maximum" -> toType(getMaximum(), type);
683         case "maxItems" -> toType(getMaxItems(), type);
684         case "maxLength" -> toType(getMaxLength(), type);
685         case "minimum" -> toType(getMinimum(), type);
686         case "minItems" -> toType(getMinItems(), type);
687         case "minLength" -> toType(getMinLength(), type);
688         case "multipleOf" -> toType(getMultipleOf(), type);
689         case "pattern" -> toType(getPattern(), type);
690         case "$ref" -> toType(getRef(), type);
691         case "type" -> toType(getType(), type);
692         case "uniqueItems" -> toType(getUniqueItems(), type);
693         default -> super.get(property, type);
694      };
695   }
696
697   @Override /* Overridden from SwaggerElement */
698   public Items set(String property, Object value) {
699      assertArgNotNull("property", property);
700      return switch (property) {
701         case "collectionFormat" -> setCollectionFormat(Utils.s(value));
702         case "default" -> setDefault(value);
703         case "enum" -> setEnum(listBuilder(Object.class).sparse().addAny(value).build());
704         case "exclusiveMaximum" -> setExclusiveMaximum(toBoolean(value));
705         case "exclusiveMinimum" -> setExclusiveMinimum(toBoolean(value));
706         case "format" -> setFormat(Utils.s(value));
707         case "items" -> setItems(toType(value,Items.class));
708         case "maximum" -> setMaximum(toNumber(value));
709         case "maxItems" -> setMaxItems(toInteger(value));
710         case "maxLength" -> setMaxLength(toInteger(value));
711         case "minimum" -> setMinimum(toNumber(value));
712         case "minItems" -> setMinItems(toInteger(value));
713         case "minLength" -> setMinLength(toInteger(value));
714         case "multipleOf" -> setMultipleOf(toNumber(value));
715         case "pattern" -> setPattern(Utils.s(value));
716         case "$ref" -> setRef(Utils.s(value));
717         case "type" -> setType(Utils.s(value));
718         case "uniqueItems" -> setUniqueItems(toBoolean(value));
719         default -> {
720            super.set(property, value);
721            yield this;
722         }
723      };
724   }
725
726   @Override /* Overridden from SwaggerElement */
727   public Set<String> keySet() {
728      var s = setBuilder(String.class)
729         .addIf(collectionFormat != null, "collectionFormat")
730         .addIf(_default != null, "default")
731         .addIf(_enum != null, "enum")
732         .addIf(exclusiveMaximum != null, "exclusiveMaximum")
733         .addIf(exclusiveMinimum != null, "exclusiveMinimum")
734         .addIf(format != null, "format")
735         .addIf(items != null, "items")
736         .addIf(maximum != null, "maximum")
737         .addIf(maxItems != null, "maxItems")
738         .addIf(maxLength != null, "maxLength")
739         .addIf(minimum != null, "minimum")
740         .addIf(minItems != null, "minItems")
741         .addIf(minLength != null, "minLength")
742         .addIf(multipleOf != null, "multipleOf")
743         .addIf(pattern != null, "pattern")
744         .addIf(ref != null, "$ref")
745         .addIf(type != null, "type")
746         .addIf(uniqueItems != null, "uniqueItems")
747         .build();
748      return new MultiSet<>(s, super.keySet());
749   }
750
751   /**
752    * Resolves any <js>"$ref"</js> attributes in this element.
753    *
754    * @param swagger The swagger document containing the definitions.
755    * @param refStack Keeps track of previously-visited references so that we don't cause recursive loops.
756    * @param maxDepth
757    *    The maximum depth to resolve references.
758    *    <br>After that level is reached, <c>$ref</c> references will be left alone.
759    *    <br>Useful if you have very complex models and you don't want your swagger page to be overly-complex.
760    * @return
761    *    This object with references resolved.
762    *    <br>May or may not be the same object.
763    */
764   public Items resolveRefs(Swagger swagger, Deque<String> refStack, int maxDepth) {
765
766      if (ref != null) {
767         if (refStack.contains(ref) || refStack.size() >= maxDepth)
768            return this;
769         refStack.addLast(ref);
770         Items r = swagger.findRef(ref, Items.class).resolveRefs(swagger, refStack, maxDepth);
771         refStack.removeLast();
772         return r;
773      }
774
775      if (items != null)
776         items = items.resolveRefs(swagger, refStack, maxDepth);
777
778      return this;
779   }
780}