View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.juneau.bean.openapi3;
18  
19  import static org.apache.juneau.commons.utils.AssertionUtils.*;
20  import static org.apache.juneau.commons.utils.CollectionUtils.*;
21  import static org.apache.juneau.commons.utils.Utils.*;
22  import static org.apache.juneau.internal.ConverterUtils.*;
23  
24  import java.util.*;
25  
26  import org.apache.juneau.commons.collections.*;
27  
28  /**
29   * A metadata object that allows for more fine-tuned XML model definitions.
30   *
31   * <p>
32   * The Xml Object is a metadata object that allows for more fine-tuned XML model definitions. When using arrays,
33   * XML element names are not inferred (for singular/plural forms) and the name property should be used to add that
34   * information. This object is used to control how schema properties are serialized to XML.
35   *
36   * <h5 class='section'>OpenAPI Specification:</h5>
37   * <p>
38   * The Xml Object is composed of the following fields:
39   * <ul class='spaced-list'>
40   * 	<li><c>name</c> (string) - Replaces the name of the element/attribute used for the described schema property
41   * 	<li><c>namespace</c> (string) - The URI of the namespace definition
42   * 	<li><c>prefix</c> (string) - The prefix to be used for the name
43   * 	<li><c>attribute</c> (boolean) - Declares whether the property definition translates to an attribute instead of an element
44   * 	<li><c>wrapped</c> (boolean) - May be used only for an array definition. Signifies whether the array is wrapped
45   * </ul>
46   *
47   * <h5 class='section'>Example:</h5>
48   * <p class='bcode'>
49   * 	<jc>// Construct using SwaggerBuilder.</jc>
50   * 	Xml <jv>x</jv> = <jsm>xml</jsm>().setName(<js>"book"</js>).setNamespace(<js>"http://example.com/schema"</js>);
51   *
52   * 	<jc>// Serialize using JsonSerializer.</jc>
53   * 	String <jv>json</jv> = Json.<jsm>from</jsm>(<jv>x</jv>);
54   *
55   * 	<jc>// Or just use toString() which does the same as above.</jc>
56   * 	<jv>json</jv> = <jv>x</jv>.toString();
57   * </p>
58   * <p class='bcode'>
59   * 	<jc>// Output</jc>
60   * 	{
61   * 		<js>"name"</js>: <js>"book"</js>,
62   * 		<js>"namespace"</js>: <js>"http://example.com/schema"</js>
63   * 	}
64   * </p>
65   *
66   * <h5 class='section'>See Also:</h5><ul>
67   * 	<li class='link'><a class="doclink" href="https://spec.openapis.org/oas/v3.0.0#xml-object">OpenAPI Specification &gt; XML Object</a>
68   * 	<li class='link'><a class="doclink" href="https://swagger.io/docs/specification/data-models/representing-xml/">OpenAPI Representing XML</a>
69   * 	<li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauBeanOpenApi3">juneau-bean-openapi-v3</a>
70   * </ul>
71   */
72  public class Xml extends OpenApiElement {
73  
74  	private String name, namespace, prefix;
75  	private Boolean attribute, wrapped;
76  
77  	/**
78  	 * Default constructor.
79  	 */
80  	public Xml() {}
81  
82  	/**
83  	 * Copy constructor.
84  	 *
85  	 * @param copyFrom The object to copy.
86  	 */
87  	public Xml(Xml copyFrom) {
88  		super(copyFrom);
89  
90  		this.name = copyFrom.name;
91  		this.namespace = copyFrom.namespace;
92  		this.prefix = copyFrom.prefix;
93  		this.attribute = copyFrom.attribute;
94  		this.wrapped = copyFrom.wrapped;
95  	}
96  
97  	/**
98  	 * Make a deep copy of this object.
99  	 *
100 	 * @return A deep copy of this object.
101 	 */
102 	public Xml copy() {
103 		return new Xml(this);
104 	}
105 
106 	@Override /* Overridden from OpenApiElement */
107 	public <T> T get(String property, Class<T> type) {
108 		assertArgNotNull("property", property);
109 		return switch (property) {
110 			case "name" -> toType(getName(), type);
111 			case "namespace" -> toType(getNamespace(), type);
112 			case "prefix" -> toType(getPrefix(), type);
113 			case "attribute" -> toType(getAttribute(), type);
114 			case "wrapped" -> toType(getWrapped(), type);
115 			default -> super.get(property, type);
116 		};
117 	}
118 
119 	/**
120 	 * Bean property getter:  <property>attribute</property>.
121 	 *
122 	 * <p>
123 	 * Declares whether the property definition translates to an attribute instead of an element.
124 	 *
125 	 * @return The property value, or <jk>null</jk> if it is not set.
126 	 */
127 	public Boolean getAttribute() { return attribute; }
128 
129 	/**
130 	 * Bean property getter:  <property>name</property>.
131 	 *
132 	 * <p>
133 	 * Replaces the name of the element/attribute used for the described schema property.
134 	 *
135 	 * <p>
136 	 * When defined within the Items Object (<code>items</code>), it will affect the name of the individual XML elements
137 	 * within the list.
138 	 * <br>When defined alongside <code>type</code> being array (outside the <code>items</code>), it will affect the
139 	 * wrapping element and only if wrapped is <jk>true</jk>.
140 	 * <br>If wrapped is <jk>false</jk>, it will be ignored.
141 	 *
142 	 * @return The property value, or <jk>null</jk> if it is not set.
143 	 */
144 	public String getName() { return name; }
145 
146 	/**
147 	 * Bean property getter:  <property>namespace</property>.
148 	 *
149 	 * <p>
150 	 * The URL of the namespace definition. Value SHOULD be in the form of a URL.
151 	 *
152 	 * @return The property value, or <jk>null</jk> if it is not set.
153 	 */
154 	public String getNamespace() { return namespace; }
155 
156 	/**
157 	 * Bean property getter:  <property>prefix</property>.
158 	 *
159 	 * <p>
160 	 * The prefix to be used for the name.
161 	 *
162 	 * @return The property value, or <jk>null</jk> if it is not set.
163 	 */
164 	public String getPrefix() { return prefix; }
165 
166 	/**
167 	 * Bean property getter:  <property>wrapped</property>.
168 	 *
169 	 * <p>
170 	 * MAY be used only for an array definition.
171 	 *
172 	 * <p>
173 	 * Signifies whether the array is wrapped (for example,
174 	 * <code>&lt;books&gt;&lt;book/&gt;&lt;book/&gt;&lt;books&gt;</code>) or unwrapped
175 	 * (<code>&lt;book/&gt;&lt;book/&gt;</code>).
176 	 * <br>The definition takes effect only when defined alongside <code>type</code> being <code>array</code>
177 	 * (outside the <code>items</code>).
178 	 *
179 	 * @return The property value, or <jk>null</jk> if it is not set.
180 	 */
181 	public Boolean getWrapped() { return wrapped; }
182 
183 	@Override /* Overridden from OpenApiElement */
184 	public Set<String> keySet() {
185 		// @formatter:off
186 		var s = setb(String.class)
187 			.addIf(nn(attribute), "attribute")
188 			.addIf(nn(name), "name")
189 			.addIf(nn(namespace), "namespace")
190 			.addIf(nn(prefix), "prefix")
191 			.addIf(nn(wrapped), "wrapped")
192 			.build();
193 		// @formatter:on
194 		return new MultiSet<>(s, super.keySet());
195 	}
196 
197 	@Override /* Overridden from OpenApiElement */
198 	public Xml set(String property, Object value) {
199 		assertArgNotNull("property", property);
200 		return switch (property) {
201 			case "attribute" -> setAttribute(toBoolean(value));
202 			case "name" -> setName(s(value));
203 			case "namespace" -> setNamespace(s(value));
204 			case "prefix" -> setPrefix(s(value));
205 			case "wrapped" -> setWrapped(toBoolean(value));
206 			default -> {
207 				super.set(property, value);
208 				yield this;
209 			}
210 		};
211 	}
212 
213 	/**
214 	 * Bean property setter:  <property>attribute</property>.
215 	 *
216 	 * <p>
217 	 * Declares whether the property definition translates to an attribute instead of an element.
218 	 *
219 	 * @param value
220 	 * 	The new value for this property.
221 	 * 	<br>Default value is <jk>false</jk>.
222 	 * 	<br>Can be <jk>null</jk> to unset the property.
223 	 * @return This object
224 	 */
225 	public Xml setAttribute(Boolean value) {
226 		attribute = value;
227 		return this;
228 	}
229 
230 	/**
231 	 * Bean property setter:  <property>name</property>.
232 	 *
233 	 * <p>
234 	 * Replaces the name of the element/attribute used for the described schema property.
235 	 *
236 	 * <p>
237 	 * When defined within the Items Object (<code>items</code>), it will affect the name of the individual XML elements
238 	 * within the list.
239 	 * <br>When defined alongside <code>type</code> being array (outside the <code>items</code>), it will affect the
240 	 * wrapping element and only if wrapped is <jk>true</jk>.
241 	 * <br>If wrapped is <jk>false</jk>, it will be ignored.
242 	 *
243 	 * @param value
244 	 * 	The new value for this property.
245 	 * 	<br>Can be <jk>null</jk> to unset the property.
246 	 * @return This object
247 	 */
248 	public Xml setName(String value) {
249 		name = value;
250 		return this;
251 	}
252 
253 	/**
254 	 * Bean property setter:  <property>namespace</property>.
255 	 *
256 	 * <p>
257 	 * The URL of the namespace definition. Value SHOULD be in the form of a URL.
258 	 *
259 	 * @param value
260 	 * 	The new value for this property.
261 	 * 	<br>Can be <jk>null</jk> to unset the property.
262 	 * @return This object
263 	 */
264 	public Xml setNamespace(String value) {
265 		namespace = value;
266 		return this;
267 	}
268 
269 	/**
270 	 * Bean property setter:  <property>prefix</property>.
271 	 *
272 	 * <p>
273 	 * The prefix to be used for the name.
274 	 *
275 	 * @param value
276 	 * 	The new value for this property.
277 	 * 	<br>Can be <jk>null</jk> to unset the property.
278 	 * @return This object
279 	 */
280 	public Xml setPrefix(String value) {
281 		prefix = value;
282 		return this;
283 	}
284 
285 	/**
286 	 * Bean property setter:  <property>wrapped</property>.
287 	 *
288 	 * <p>
289 	 * MAY be used only for an array definition.
290 	 *
291 	 * <p>
292 	 * Signifies whether the array is wrapped (for example,
293 	 * <code>&lt;books&gt;&lt;book/&gt;&lt;book/&gt;&lt;books&gt;</code>) or unwrapped
294 	 * (<code>&lt;book/&gt;&lt;book/&gt;</code>).
295 	 * <br>The definition takes effect only when defined alongside <code>type</code> being <code>array</code>
296 	 * (outside the <code>items</code>).
297 	 *
298 	 * @param value
299 	 * 	The new value for this property.
300 	 * 	<br>Can be <jk>null</jk> to unset the property.
301 	 * @return This object
302 	 */
303 	public Xml setWrapped(Boolean value) {
304 		wrapped = value;
305 		return this;
306 	}
307 
308 	@Override /* Overridden from OpenApiElement */
309 	public Xml strict() {
310 		super.strict();
311 		return this;
312 	}
313 
314 	@Override /* Overridden from OpenApiElement */
315 	public Xml strict(Object value) {
316 		super.strict(value);
317 		return this;
318 	}
319 }