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