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.commons.utils.AssertionUtils.*;
020import static org.apache.juneau.commons.utils.CollectionUtils.*;
021import static org.apache.juneau.commons.utils.Utils.*;
022import static org.apache.juneau.internal.ConverterUtils.*;
023
024import java.util.*;
025
026import org.apache.juneau.commons.collections.*;
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 name, namespace, prefix;
077   private Boolean attribute, wrapped;
078
079   /**
080    * Default constructor.
081    */
082   public Xml() {}
083
084   /**
085    * Copy constructor.
086    *
087    * @param copyFrom The object to copy.
088    */
089   public Xml(Xml copyFrom) {
090      super(copyFrom);
091
092      this.attribute = copyFrom.attribute;
093      this.name = copyFrom.name;
094      this.namespace = copyFrom.namespace;
095      this.prefix = copyFrom.prefix;
096      this.wrapped = copyFrom.wrapped;
097   }
098
099   /**
100    * Make a deep copy of this object.
101    *
102    * @return A deep copy of this object.
103    */
104   public Xml copy() {
105      return new Xml(this);
106   }
107
108   @Override /* Overridden from SwaggerElement */
109   public <T> T get(String property, Class<T> type) {
110      assertArgNotNull("property", property);
111      return switch (property) {
112         case "attribute" -> toType(getAttribute(), type);
113         case "name" -> toType(getName(), type);
114         case "namespace" -> toType(getNamespace(), type);
115         case "prefix" -> toType(getPrefix(), type);
116         case "wrapped" -> toType(getWrapped(), type);
117         default -> super.get(property, type);
118      };
119   }
120
121   /**
122    * Bean property getter:  <property>attribute</property>.
123    *
124    * <p>
125    * Declares whether the property definition translates to an attribute instead of an element.
126    *
127    * @return The property value, or <jk>null</jk> if it is not set.
128    */
129   public Boolean getAttribute() { return attribute; }
130
131   /**
132    * Bean property getter:  <property>name</property>.
133    *
134    * <p>
135    * The name of the element/attribute used for the described schema property.
136    *
137    * @return The property value, or <jk>null</jk> if it is not set.
138    */
139   public String getName() { return name; }
140
141   /**
142    * Bean property getter:  <property>namespace</property>.
143    *
144    * <p>
145    * The URL of the namespace definition.
146    *
147    * @return The property value, or <jk>null</jk> if it is not set.
148    */
149   public String getNamespace() { return namespace; }
150
151   /**
152    * Bean property getter:  <property>prefix</property>.
153    *
154    * <p>
155    * The prefix to be used for the name.
156    *
157    * @return The property value, or <jk>null</jk> if it is not set.
158    */
159   public String getPrefix() { return prefix; }
160
161   /**
162    * Bean property getter:  <property>wrapped</property>.
163    *
164    * <p>
165    * Signifies whether the array is wrapped (for example,
166    * <c>&lt;books&gt;&lt;book/&gt;&lt;book/&gt;&lt;books&gt;</c>) or unwrapped
167    * (<c>&lt;book/&gt;&lt;book/&gt;</c>).
168    * <br>The definition takes effect only when defined alongside <c>type</c> being <c>array</c>
169    * (outside the <c>items</c>).
170    *
171    * @return The property value, or <jk>null</jk> if it is not set.
172    */
173   public Boolean getWrapped() { return wrapped; }
174
175   @Override /* Overridden from SwaggerElement */
176   public Set<String> keySet() {
177      // @formatter:off
178      var s = setb(String.class)
179         .addIf(nn(attribute), "attribute")
180         .addIf(nn(name), "name")
181         .addIf(nn(namespace), "namespace")
182         .addIf(nn(prefix), "prefix")
183         .addIf(nn(wrapped), "wrapped")
184         .build();
185      // @formatter:on
186      return new MultiSet<>(s, super.keySet());
187   }
188
189   @Override /* Overridden from SwaggerElement */
190   public Xml set(String property, Object value) {
191      assertArgNotNull("property", property);
192      return switch (property) {
193         case "attribute" -> setAttribute(toBoolean(value));
194         case "name" -> setName(s(value));
195         case "namespace" -> setNamespace(s(value));
196         case "prefix" -> setPrefix(s(value));
197         case "wrapped" -> setWrapped(toBoolean(value));
198         default -> {
199            super.set(property, value);
200            yield this;
201         }
202      };
203   }
204
205   /**
206    * Bean property setter:  <property>attribute</property>.
207    *
208    * <p>
209    * Declares whether the property definition translates to an attribute instead of an element.
210    *
211    * @param value
212    *    The new value for this property.
213    *    <br>Default value is <jk>false</jk>.
214    *    <br>Can be <jk>null</jk> to unset the property.
215    * @return This object.
216    */
217   public Xml setAttribute(Boolean value) {
218      attribute = value;
219      return this;
220   }
221
222   /**
223    * Bean property setter:  <property>name</property>.
224    *
225    * <p>
226    * The name of the element/attribute used for the described schema property.
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.
232    */
233   public Xml setName(String value) {
234      name = value;
235      return this;
236   }
237
238   /**
239    * Bean property setter:  <property>namespace</property>.
240    *
241    * <p>
242    * The URL of the namespace definition.
243    *
244    * @param value
245    *    The new value for this property.
246    *    <br>Can be <jk>null</jk> to unset the property.
247    * @return This object.
248    */
249   public Xml setNamespace(String value) {
250      namespace = value;
251      return this;
252   }
253
254   /**
255    * Bean property setter:  <property>prefix</property>.
256    *
257    * <p>
258    * The prefix to be used for the name.
259    *
260    * @param value
261    *    The new value for this property.
262    *    <br>Can be <jk>null</jk> to unset the property.
263    * @return This object.
264    */
265   public Xml setPrefix(String value) {
266      prefix = value;
267      return this;
268   }
269
270   /**
271    * Bean property setter:  <property>wrapped</property>.
272    *
273    *
274    * <p>
275    * Signifies whether the array is wrapped (for example,
276    * <c>&lt;books&gt;&lt;book/&gt;&lt;book/&gt;&lt;books&gt;</c>) or unwrapped
277    * (<c>&lt;book/&gt;&lt;book/&gt;</c>).
278    * <br>The definition takes effect only when defined alongside <c>type</c> being <c>array</c>
279    * (outside the <c>items</c>).
280    *
281    * @param value
282    *    The new value for this property.
283    *    <br>Can be <jk>null</jk> to unset the property.
284    * @return This object.
285    */
286   public Xml setWrapped(Boolean value) {
287      wrapped = value;
288      return this;
289   }
290
291   /**
292    * Sets strict mode on this bean.
293    *
294    * @return This object.
295    */
296   @Override
297   public Xml strict() {
298      super.strict();
299      return this;
300   }
301
302   /**
303    * Sets strict mode on this bean.
304    *
305    * @param value
306    *    The new value for this property.
307    *    <br>Non-boolean values will be converted to boolean using <code>Boolean.<jsm>valueOf</jsm>(value.toString())</code>.
308    *    <br>Can be <jk>null</jk> (interpreted as <jk>false</jk>).
309    * @return This object.
310    */
311   @Override
312   public Xml strict(Object value) {
313      super.strict(value);
314      return this;
315   }
316}