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.openapi3; 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.net.*; 025import java.util.*; 026 027import org.apache.juneau.*; 028import org.apache.juneau.commons.collections.*; 029 030/** 031 * Describes a single request body. 032 * 033 * <p> 034 * The Request Body Object describes a single request body that can be sent to an API operation. It includes 035 * a description, whether the request body is required, and the content (media types) that the request body can contain. 036 * 037 * <h5 class='section'>OpenAPI Specification:</h5> 038 * <p> 039 * The Request Body Object is composed of the following fields: 040 * <ul class='spaced-list'> 041 * <li><c>description</c> (string) - A brief description of the request body (CommonMark syntax may be used) 042 * <li><c>content</c> (map of {@link MediaType}, REQUIRED) - The content of the request body (keys are media types) 043 * <li><c>required</c> (boolean) - Determines if the request body is required in the request (default is <jk>false</jk>) 044 * </ul> 045 * 046 * <h5 class='section'>Example:</h5> 047 * <p class='bjava'> 048 * <jc>// Create a request body for JSON content</jc> 049 * RequestBodyInfo <jv>requestBody</jv> = <jk>new</jk> RequestBodyInfo() 050 * .setDescription(<js>"Pet object that needs to be added to the store"</js>) 051 * .setRequired(<jk>true</jk>) 052 * .setContent( 053 * JsonMap.<jsm>of</jsm>( 054 * <js>"application/json"</js>, <jk>new</jk> MediaType() 055 * .setSchema( 056 * <jk>new</jk> SchemaInfo().setRef(<js>"#/components/schemas/Pet"</js>) 057 * ) 058 * ) 059 * ); 060 * </p> 061 * 062 * <h5 class='section'>See Also:</h5><ul> 063 * <li class='link'><a class="doclink" href="https://spec.openapis.org/oas/v3.0.0#request-body-object">OpenAPI Specification > Request Body Object</a> 064 * <li class='link'><a class="doclink" href="https://swagger.io/docs/specification/describing-request-body/">OpenAPI Describing Request Body</a> 065 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauBeanOpenApi3">juneau-bean-openapi-v3</a> 066 * </ul> 067 */ 068public class RequestBodyInfo extends OpenApiElement { 069 070 private String description; 071 private Map<String,MediaType> content = map(); 072 private Boolean required; 073 074 /** 075 * Default constructor. 076 */ 077 public RequestBodyInfo() {} 078 079 /** 080 * Copy constructor. 081 * 082 * @param copyFrom The object to copy. 083 */ 084 public RequestBodyInfo(RequestBodyInfo copyFrom) { 085 super(copyFrom); 086 087 this.description = copyFrom.description; 088 this.required = copyFrom.required; 089 if (nn(copyFrom.content)) 090 content.putAll(copyOf(copyFrom.content, MediaType::copy)); 091 } 092 093 /** 094 * Adds one or more values to the <property>content</property> property. 095 * 096 * @param key The mapping key. Must not be <jk>null</jk>. 097 * @param value 098 * The values to add to this property. 099 * <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}