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.common.utils.*;
026import org.apache.juneau.internal.*;
027
028/**
029 * A metadata object that allows for more fine-tuned XML model definitions.
030 *
031 * <p>
032 * The Xml Object is a metadata object that allows for more fine-tuned XML model definitions in Swagger 2.0. When using 
033 * arrays, XML element names are not inferred (for singular/plural forms) and the name property should be used to add 
034 * that information. This object is used to control how schema properties are serialized to XML.
035 *
036 * <h5 class='section'>Swagger Specification:</h5>
037 * <p>
038 * The Xml Object is composed of the following fields:
039 * <ul class='spaced-list'>
040 *    <li><c>name</c> (string) - Replaces the name of the element/attribute used for the described schema property
041 *    <li><c>namespace</c> (string) - The URI of the namespace definition
042 *    <li><c>prefix</c> (string) - The prefix to be used for the name
043 *    <li><c>attribute</c> (boolean) - Declares whether the property definition translates to an attribute instead of an element
044 *    <li><c>wrapped</c> (boolean) - May be used only for an array definition. Signifies whether the array is wrapped
045 * </ul>
046 *
047 * <h5 class='section'>Example:</h5>
048 * <p class='bjava'>
049 *    <jc>// Construct using SwaggerBuilder.</jc>
050 *    Xml <jv>xml</jv> = <jsm>xml</jsm>()
051 *       .name(<js>"foo"</js>)
052 *       .namespace(<js>"http://foo"</js>)
053 *
054 *    <jc>// Serialize using JsonSerializer.</jc>
055 *    String <jv>json</jv> = Json.<jsm>from</jsm>(<jv>xml</jv>);
056 *
057 *    <jc>// Or just use toString() which does the same as above.</jc>
058 *  <jv>json</jv> = <jv>xml</jv>.toString();
059 * </p>
060 * <p class='bjson'>
061 *    <jc>// Output</jc>
062 *    {
063 *       <js>"name"</js>: <js>"foo"</js>,
064 *       <js>"namespace"</js>: <js>"http://foo"</js>
065 *    }
066 * </p>
067 *
068 * <h5 class='section'>See Also:</h5><ul>
069 *    <li class='link'><a class="doclink" href="https://swagger.io/specification/v2/#xml-object">Swagger 2.0 Specification &gt; XML Object</a>
070 *    <li class='link'><a class="doclink" href="https://swagger.io/docs/specification/2-0/describing-models/">Swagger Describing Models</a>
071 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauBeanSwagger2">juneau-bean-swagger-v2</a>
072 * </ul>
073 */
074public class Xml extends SwaggerElement {
075
076   private String
077      name,
078      namespace,
079      prefix;
080   private Boolean
081      attribute,
082      wrapped;
083
084   /**
085    * Default constructor.
086    */
087   public Xml() {}
088
089   /**
090    * Copy constructor.
091    *
092    * @param copyFrom The object to copy.
093    */
094   public Xml(Xml copyFrom) {
095      super(copyFrom);
096
097      this.attribute = copyFrom.attribute;
098      this.name = copyFrom.name;
099      this.namespace = copyFrom.namespace;
100      this.prefix = copyFrom.prefix;
101      this.wrapped = copyFrom.wrapped;
102   }
103
104   /**
105    * Make a deep copy of this object.
106    *
107    * @return A deep copy of this object.
108    */
109   public Xml copy() {
110      return new Xml(this);
111   }
112
113   //-----------------------------------------------------------------------------------------------------------------
114   // Properties
115   //-----------------------------------------------------------------------------------------------------------------
116
117   /**
118    * Bean property getter:  <property>attribute</property>.
119    *
120    * <p>
121    * Declares whether the property definition translates to an attribute instead of an element.
122    *
123    * @return The property value, or <jk>null</jk> if it is not set.
124    */
125   public Boolean getAttribute() {
126      return attribute;
127   }
128
129   /**
130    * Bean property setter:  <property>attribute</property>.
131    *
132    * <p>
133    * Declares whether the property definition translates to an attribute instead of an element.
134    *
135    * @param value
136    *    The new value for this property.
137    *    <br>Default value is <jk>false</jk>.
138    *    <br>Can be <jk>null</jk> to unset the property.
139    * @return This object.
140    */
141   public Xml setAttribute(Boolean value) {
142      attribute = value;
143      return this;
144   }
145
146   /**
147    * Bean property getter:  <property>name</property>.
148    *
149    * <p>
150    * The name of the element/attribute used for the described schema property.
151    *
152    * @return The property value, or <jk>null</jk> if it is not set.
153    */
154   public String getName() {
155      return name;
156   }
157
158   /**
159    * Bean property setter:  <property>name</property>.
160    *
161    * <p>
162    * The name of the element/attribute used for the described schema property.
163    *
164    * @param value
165    *    The new value for this property.
166    *    <br>Can be <jk>null</jk> to unset the property.
167    * @return This object.
168    */
169   public Xml setName(String value) {
170      name = value;
171      return this;
172   }
173
174   /**
175    * Bean property getter:  <property>namespace</property>.
176    *
177    * <p>
178    * The URL of the namespace definition.
179    *
180    * @return The property value, or <jk>null</jk> if it is not set.
181    */
182   public String getNamespace() {
183      return namespace;
184   }
185
186   /**
187    * Bean property setter:  <property>namespace</property>.
188    *
189    * <p>
190    * The URL of the namespace definition.
191    *
192    * @param value
193    *    The new value for this property.
194    *    <br>Can be <jk>null</jk> to unset the property.
195    * @return This object.
196    */
197   public Xml setNamespace(String value) {
198      namespace = value;
199      return this;
200   }
201
202   /**
203    * Bean property getter:  <property>prefix</property>.
204    *
205    * <p>
206    * The prefix to be used for the name.
207    *
208    * @return The property value, or <jk>null</jk> if it is not set.
209    */
210   public String getPrefix() {
211      return prefix;
212   }
213
214   /**
215    * Bean property setter:  <property>prefix</property>.
216    *
217    * <p>
218    * The prefix to be used for the name.
219    *
220    * @param value
221    *    The new value for this property.
222    *    <br>Can be <jk>null</jk> to unset the property.
223    * @return This object.
224    */
225   public Xml setPrefix(String value) {
226      prefix = value;
227      return this;
228   }
229
230   /**
231    * Bean property getter:  <property>wrapped</property>.
232    *
233    * <p>
234    * Signifies whether the array is wrapped (for example,
235    * <c>&lt;books&gt;&lt;book/&gt;&lt;book/&gt;&lt;books&gt;</c>) or unwrapped
236    * (<c>&lt;book/&gt;&lt;book/&gt;</c>).
237    * <br>The definition takes effect only when defined alongside <c>type</c> being <c>array</c>
238    * (outside the <c>items</c>).
239    *
240    * @return The property value, or <jk>null</jk> if it is not set.
241    */
242   public Boolean getWrapped() {
243      return wrapped;
244   }
245
246   /**
247    * Bean property setter:  <property>wrapped</property>.
248    *
249    *
250    * <p>
251    * Signifies whether the array is wrapped (for example,
252    * <c>&lt;books&gt;&lt;book/&gt;&lt;book/&gt;&lt;books&gt;</c>) or unwrapped
253    * (<c>&lt;book/&gt;&lt;book/&gt;</c>).
254    * <br>The definition takes effect only when defined alongside <c>type</c> being <c>array</c>
255    * (outside the <c>items</c>).
256    *
257    * @param value
258    *    The new value for this property.
259    *    <br>Can be <jk>null</jk> to unset the property.
260    * @return This object.
261    */
262   public Xml setWrapped(Boolean value) {
263      this.wrapped = value;
264      return this;
265   }
266
267   @Override /* Overridden from SwaggerElement */
268   public <T> T get(String property, Class<T> type) {
269      assertArgNotNull("property", property);
270      return switch (property) {
271         case "attribute" -> toType(getAttribute(), type);
272         case "name" -> toType(getName(), type);
273         case "namespace" -> toType(getNamespace(), type);
274         case "prefix" -> toType(getPrefix(), type);
275         case "wrapped" -> toType(getWrapped(), type);
276         default -> super.get(property, type);
277      };
278   }
279
280   @Override /* Overridden from SwaggerElement */
281   public Xml set(String property, Object value) {
282      assertArgNotNull("property", property);
283      return switch (property) {
284         case "attribute" -> setAttribute(toBoolean(value));
285         case "name" -> setName(Utils.s(value));
286         case "namespace" -> setNamespace(Utils.s(value));
287         case "prefix" -> setPrefix(Utils.s(value));
288         case "wrapped" -> setWrapped(toBoolean(value));
289         default -> {
290            super.set(property, value);
291            yield this;
292         }
293      };
294   }
295
296   @Override /* Overridden from SwaggerElement */
297   public Set<String> keySet() {
298      var s = setBuilder(String.class)
299         .addIf(attribute != null, "attribute")
300         .addIf(name != null, "name")
301         .addIf(namespace != null, "namespace")
302         .addIf(prefix != null, "prefix")
303         .addIf(wrapped != null, "wrapped")
304         .build();
305      return new MultiSet<>(s, super.keySet());
306   }
307
308   /**
309    * Sets strict mode on this bean.
310    *
311    * @return This object.
312    */
313   @Override
314   public Xml strict() {
315      super.strict();
316      return this;
317   }
318
319   /**
320    * Sets strict mode on this bean.
321    *
322    * @param value
323    *    The new value for this property.
324    *    <br>Non-boolean values will be converted to boolean using <code>Boolean.<jsm>valueOf</jsm>(value.toString())</code>.
325    *    <br>Can be <jk>null</jk> (interpreted as <jk>false</jk>).
326    * @return This object.
327    */
328   @Override
329   public Xml strict(Object value) {
330      super.strict(value);
331      return this;
332   }
333
334}