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.net.*;
25  import java.util.*;
26  
27  import org.apache.juneau.*;
28  import org.apache.juneau.commons.collections.*;
29  
30  /**
31   * Describes a single request body.
32   *
33   * <p>
34   * The Request Body Object describes a single request body that can be sent to an API operation. It includes
35   * a description, whether the request body is required, and the content (media types) that the request body can contain.
36   *
37   * <h5 class='section'>OpenAPI Specification:</h5>
38   * <p>
39   * The Request Body Object is composed of the following fields:
40   * <ul class='spaced-list'>
41   * 	<li><c>description</c> (string) - A brief description of the request body (CommonMark syntax may be used)
42   * 	<li><c>content</c> (map of {@link MediaType}, REQUIRED) - The content of the request body (keys are media types)
43   * 	<li><c>required</c> (boolean) - Determines if the request body is required in the request (default is <jk>false</jk>)
44   * </ul>
45   *
46   * <h5 class='section'>Example:</h5>
47   * <p class='bjava'>
48   * 	<jc>// Create a request body for JSON content</jc>
49   * 	RequestBodyInfo <jv>requestBody</jv> = <jk>new</jk> RequestBodyInfo()
50   * 		.setDescription(<js>"Pet object that needs to be added to the store"</js>)
51   * 		.setRequired(<jk>true</jk>)
52   * 		.setContent(
53   * 			JsonMap.<jsm>of</jsm>(
54   * 				<js>"application/json"</js>, <jk>new</jk> MediaType()
55   * 					.setSchema(
56   * 						<jk>new</jk> SchemaInfo().setRef(<js>"#/components/schemas/Pet"</js>)
57   * 					)
58   * 			)
59   * 		);
60   * </p>
61   *
62   * <h5 class='section'>See Also:</h5><ul>
63   * 	<li class='link'><a class="doclink" href="https://spec.openapis.org/oas/v3.0.0#request-body-object">OpenAPI Specification &gt; Request Body Object</a>
64   * 	<li class='link'><a class="doclink" href="https://swagger.io/docs/specification/describing-request-body/">OpenAPI Describing Request Body</a>
65   * 	<li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauBeanOpenApi3">juneau-bean-openapi-v3</a>
66   * </ul>
67   */
68  public class RequestBodyInfo extends OpenApiElement {
69  
70  	private String description;
71  	private Map<String,MediaType> content = map();
72  	private Boolean required;
73  
74  	/**
75  	 * Default constructor.
76  	 */
77  	public RequestBodyInfo() {}
78  
79  	/**
80  	 * Copy constructor.
81  	 *
82  	 * @param copyFrom The object to copy.
83  	 */
84  	public RequestBodyInfo(RequestBodyInfo copyFrom) {
85  		super(copyFrom);
86  
87  		this.description = copyFrom.description;
88  		this.required = copyFrom.required;
89  		if (nn(copyFrom.content))
90  			content.putAll(copyOf(copyFrom.content, MediaType::copy));
91  	}
92  
93  	/**
94  	 * Adds one or more values to the <property>content</property> property.
95  	 *
96  	 * @param key The mapping key.  Must not be <jk>null</jk>.
97  	 * @param value
98  	 * 	The values to add to this property.
99  	 * 	<br>Must not be <jk>null</jk>.
100 	 * 	<br>Ignored if <jk>null</jk>.
101 	 * @return This object
102 	 */
103 	public RequestBodyInfo addContent(String key, MediaType value) {
104 		assertArgNotNull("key", key);
105 		assertArgNotNull("value", value);
106 		content.put(key, value);
107 		return this;
108 	}
109 
110 	/**
111 	 * Make a deep copy of this object.
112 	 *
113 	 * @return A deep copy of this object.
114 	 */
115 	public RequestBodyInfo copy() {
116 		return new RequestBodyInfo(this);
117 	}
118 
119 	@Override /* Overridden from OpenApiElement */
120 	public <T> T get(String property, Class<T> type) {
121 		assertArgNotNull("property", property);
122 		return switch (property) {
123 			case "description" -> toType(getDescription(), type);
124 			case "content" -> toType(getContent(), type);
125 			case "required" -> toType(getRequired(), type);
126 			default -> super.get(property, type);
127 		};
128 	}
129 
130 	/**
131 	 * Bean property getter:  <property>content</property>.
132 	 *
133 	 * @return The property value, or <jk>null</jk> if it is not set.
134 	 */
135 	public Map<String,MediaType> getContent() { return nullIfEmpty(content); }
136 
137 	/**
138 	 * Bean property getter:  <property>contentType</property>.
139 	 *
140 	 * <p>
141 	 * The URL pointing to the contact information.
142 	 *
143 	 * @return The property value, or <jk>null</jk> if it is not set.
144 	 */
145 	public String getDescription() { return description; }
146 
147 	/**
148 	 * Bean property getter:  <property>required</property>.
149 	 *
150 	 * <p>
151 	 * The type of the object.
152 	 *
153 	 * @return The property value, or <jk>null</jk> if it is not set.
154 	 */
155 	public Boolean getRequired() { return required; }
156 
157 	@Override /* Overridden from OpenApiElement */
158 	public Set<String> keySet() {
159 		// @formatter:off
160 		var s = setb(String.class)
161 			.addIf(ne(content), "content")
162 			.addIf(nn(description), "description")
163 			.addIf(nn(required), "required")
164 			.build();
165 		// @formatter:on
166 		return new MultiSet<>(s, super.keySet());
167 	}
168 
169 	@Override /* Overridden from OpenApiElement */
170 	public RequestBodyInfo set(String property, Object value) {
171 		assertArgNotNull("property", property);
172 		return switch (property) {
173 			case "content" -> setContent(toMapBuilder(value, String.class, MediaType.class).sparse().build());
174 			case "description" -> setDescription(s(value));
175 			case "required" -> setRequired(toBoolean(value));
176 			default -> {
177 				super.set(property, value);
178 				yield this;
179 			}
180 		};
181 	}
182 
183 	/**
184 	 * Bean property setter:  <property>content</property>.
185 	 *
186 	 * @param value
187 	 * 	The new value for this property.
188 	 * 	<br>Can be <jk>null</jk> to unset the property.
189 	 * @return This object
190 	 */
191 	public RequestBodyInfo setContent(Map<String,MediaType> value) {
192 		content.clear();
193 		if (nn(value))
194 			content.putAll(value);
195 		return this;
196 	}
197 
198 	/**
199 	 * Bean property setter:  <property>url</property>.
200 	 *
201 	 * <p>
202 	 * The value can be of any of the following types: {@link URI}, {@link URL}, {@link String}.
203 	 * <br>Strings must be valid URIs.
204 	 *
205 	 * <p>
206 	 * URIs defined by {@link UriResolver} can be used for values.
207 	 *
208 	 * @param value
209 	 * 	The new value for this property.
210 	 * 	<br>Can be <jk>null</jk> to unset the property.
211 	 * @return This object
212 	 */
213 	public RequestBodyInfo setDescription(String value) {
214 		description = value;
215 		return this;
216 	}
217 
218 	/**
219 	 * Bean property setter:  <property>explode</property>.
220 	 *
221 	 * <p>
222 	 * The type of the object.
223 	 *
224 	 * @param value
225 	 * 	The new value for this property.
226 	 * 	<br>Property value is required.
227 	 * 	<br>Can be <jk>null</jk> to unset the property.
228 	 * @return This object
229 	 */
230 	public RequestBodyInfo setRequired(Boolean value) {
231 		required = value;
232 		return this;
233 	}
234 
235 	@Override /* Overridden from OpenApiElement */
236 	public RequestBodyInfo strict(Object value) {
237 		super.strict(value);
238 		return this;
239 	}
240 
241 	@Override /* Overridden from OpenApiElement */
242 	protected RequestBodyInfo strict() {
243 		super.strict();
244 		return this;
245 	}
246 }