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.CollectionUtils.*; 020import static org.apache.juneau.commons.utils.Shorts.*; 021import static org.apache.juneau.marshall.internal.ConverterUtils.*; 022 023import java.util.*; 024 025import org.apache.juneau.commons.collections.*; 026 027/** 028 * Describes a single request body. 029 * 030 * <p> 031 * The Request Body Object describes a single request body that can be sent to an API operation. It includes 032 * a description, whether the request body is required, and the content (media types) that the request body can contain. 033 * 034 * <h5 class='section'>OpenAPI Specification:</h5> 035 * <p> 036 * The Request Body Object is composed of the following fields: 037 * <ul class='spaced-list'> 038 * <li><c>description</c> (string) - A brief description of the request body (CommonMark syntax may be used) 039 * <li><c>content</c> (map of {@link MediaType}, REQUIRED) - The content of the request body (keys are media types) 040 * <li><c>required</c> (boolean) - Determines if the request body is required in the request (default is <jk>false</jk>) 041 * </ul> 042 * 043 * <h5 class='section'>Example:</h5> 044 * <p class='bjava'> 045 * <jc>// Create a request body for JSON content</jc> 046 * RequestBodyInfo <jv>requestBody</jv> = <jk>new</jk> RequestBodyInfo() 047 * .setDescription(<js>"Pet object that needs to be added to the store"</js>) 048 * .setRequired(<jk>true</jk>) 049 * .setContent( 050 * JsonMap.<jsm>of</jsm>( 051 * <js>"application/json"</js>, <jk>new</jk> MediaType() 052 * .setSchema( 053 * <jk>new</jk> SchemaInfo().setRef(<js>"#/components/schemas/Pet"</js>) 054 * ) 055 * ) 056 * ); 057 * </p> 058 * 059 * <h5 class='section'>See Also:</h5><ul> 060 * <li class='link'><a class="doclink" href="https://spec.openapis.org/oas/v3.0.0#request-body-object">OpenAPI Specification > Request Body Object</a> 061 * <li class='link'><a class="doclink" href="https://swagger.io/docs/specification/describing-request-body/">OpenAPI Describing Request Body</a> 062 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauBeanOpenApi3">juneau-bean-openapi-v3</a> 063 * </ul> 064 */ 065@SuppressWarnings({ 066 "java:S1192" // Duplicated literals (argument/property names) read more clearly inline than as constants 067}) 068public class RequestBodyInfo extends OpenApiElement { 069 070 private String description; 071 private final 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 content.putAll(cp(copyFrom.content, MediaType::copy)); 090 } 091 092 /** 093 * Adds one or more values to the <property>content</property> property. 094 * 095 * @param key The mapping key. Must not be <jk>null</jk>, or an {@link IllegalArgumentException} is thrown. 096 * @param value 097 * The values to add to this property. 098 * <br>Must not be <jk>null</jk>, or an {@link IllegalArgumentException} is thrown. 099 * <br>Ignored if <jk>null</jk>. 100 * @return This object 101 */ 102 public RequestBodyInfo addContent(String key, MediaType value) { 103 reqnn("key", key); 104 reqnn("value", value); 105 content.put(key, value); 106 return this; 107 } 108 109 /** 110 * Make a deep copy of this object. 111 * 112 * @return A deep copy of this object. 113 */ 114 public RequestBodyInfo copy() { 115 return new RequestBodyInfo(this); 116 } 117 118 @Override /* Overridden from OpenApiElement */ 119 public <T> T get(String property, Class<T> type) { 120 reqnn("property", property); 121 return switch (property) { 122 case "description" -> toType(getDescription(), type); 123 case "content" -> toType(getContent(), type); 124 case "required" -> toType(getRequired(), type); 125 default -> super.get(property, type); 126 }; 127 } 128 129 /** 130 * Bean property getter: <property>content</property>. 131 * 132 * @return The property value, or <jk>null</jk> if it is not set. 133 */ 134 public Map<String,MediaType> getContent() { return nie(content); } 135 136 /** 137 * Bean property getter: <property>description</property>. 138 * 139 * <p> 140 * A brief description of the request body. 141 * 142 * @return The property value, or <jk>null</jk> if it is not set. 143 */ 144 public String getDescription() { return description; } 145 146 /** 147 * Bean property getter: <property>required</property>. 148 * 149 * <p> 150 * Determines if the request body is required in the request. 151 * 152 * @return The property value, or <jk>null</jk> if it is not set. 153 */ 154 public Boolean getRequired() { return required; } 155 156 @Override /* Overridden from OpenApiElement */ 157 public Set<String> keySet() { 158 // @formatter:off 159 var s = stb(String.class) 160 .addIf(ine(content), "content") 161 .addIf(nn(description), "description") 162 .addIf(nn(required), "required") 163 .build(); 164 // @formatter:on 165 return new MultiSet<>(s, super.keySet()); 166 } 167 168 @Override /* Overridden from OpenApiElement */ 169 public RequestBodyInfo set(String property, Object value) { 170 reqnn("property", property); 171 return switch (property) { 172 case "content" -> setContent(toMapBuilder(value, String.class, MediaType.class).sparse().build()); 173 case "description" -> setDescription(s(value)); 174 case "required" -> setRequired(toBoolean(value)); 175 default -> { 176 super.set(property, value); 177 yield this; 178 } 179 }; 180 } 181 182 /** 183 * Bean property setter: <property>content</property>. 184 * 185 * @param value 186 * The new value for this property. 187 * <br>Can be <jk>null</jk> to unset the property. 188 * @return This object 189 */ 190 public RequestBodyInfo setContent(Map<String,MediaType> value) { 191 content.clear(); 192 if (nn(value)) 193 content.putAll(value); 194 return this; 195 } 196 197 /** 198 * Bean property setter: <property>description</property>. 199 * 200 * <p> 201 * A brief description of the request body. 202 * 203 * @param value 204 * The new value for this property. 205 * <br>Can be <jk>null</jk> to unset the property. 206 * @return This object 207 */ 208 public RequestBodyInfo setDescription(String value) { 209 description = value; 210 return this; 211 } 212 213 /** 214 * Bean property setter: <property>required</property>. 215 * 216 * <p> 217 * Determines if the request body is required in the request. 218 * 219 * @param value 220 * The new value for this property. 221 * <br>Can be <jk>null</jk> to unset the property. 222 * @return This object 223 */ 224 public RequestBodyInfo setRequired(Boolean value) { 225 required = value; 226 return this; 227 } 228 229 @Override /* Overridden from OpenApiElement */ 230 public RequestBodyInfo strict(Object value) { 231 super.strict(value); 232 return this; 233 } 234 235 @Override /* Overridden from OpenApiElement */ 236 protected RequestBodyInfo strict() { 237 super.strict(); 238 return this; 239 } 240}