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.http; 018 019import static java.lang.annotation.ElementType.*; 020import static java.lang.annotation.RetentionPolicy.*; 021 022import java.lang.annotation.*; 023 024import org.apache.juneau.commons.*; 025 026/** 027 * REST request form-data annotation. 028 * 029 * <p> 030 * Identifies a POJO to be used as a form-data entry on an HTTP request. 031 * 032 * <p> 033 * Can be used in the following locations: 034 * <ul> 035 * <li>Arguments and argument-types of server-side <ja>@RestOp</ja>-annotated methods. 036 * <li>Arguments and argument-types of client-side <ja>@RemoteResource</ja>-annotated interfaces. 037 * <li>Methods and return types of server-side and client-side <ja>@Request</ja>-annotated interfaces. 038 * </ul> 039 * 040 * <h5 class='topic'>Arguments and argument-types of server-side @RestOp-annotated methods</h5> 041 * <p> 042 * Annotation that can be applied to a parameter of a <ja>@RestOp</ja>-annotated method to identify it as a form-data parameter. 043 * 044 * <h5 class='section'>Example:</h5> 045 * <p class='bjava'> 046 * <ja>@RestPost</ja> 047 * <jk>public void</jk> doPost( 048 * <ja>@FormData</ja>(<js>"p1"</js>) <jk>int</jk> <jv>p1</jv>, 049 * <ja>@FormData</ja>(<js>"p2"</js>) String <jv>p2</jv>, 050 * <ja>@FormData</ja>(<js>"p3"</js>) UUID <jv>p3</jv> 051 * ) {...} 052 * </p> 053 * 054 * <p> 055 * This is functionally equivalent to the following code... 056 * <p class='bjava'> 057 * <ja>@RestPost</ja> 058 * <jk>public void</jk> doPost(RestRequest <jv>req</jv>) { 059 * <jk>int</jk> <jv>p1</jv> = <jv>req</jv>.getFormParam(<js>"p1"</js>).as(<jk>int</jk>.<jk>class</jk>).orElse(0); 060 * String <jv>p2</jv> = <jv>req</jv>.getFormParam(<js>"p2"</js>).asString().orElse(<jk>null</jk>); 061 * UUID <jv>p3</jv> = <jv>req</jv>.getFormParam(<js>"p3"</js>).as(UUID.<jk>class</jk>).orElse(<jk>null</jk>); 062 * ... 063 * } 064 * </p> 065 * 066 * <h5 class='section'>See Also:</h5><ul> 067 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauBeanSwagger2">juneau-bean-swagger-v2</a> 068 * <li class='extlink'><a class='doclink' href='https://swagger.io/specification/v2#parameterObject'>Swagger Parameter Object</a> 069 * </ul> 070 * 071 * <h5 class='topic'>Important note concerning FORM posts</h5> 072 * <p> 073 * This annotation should not be combined with the {@link Content @Content} annotation or <c>RestRequest.getContent()</c> method 074 * for <c>application/x-www-form-urlencoded POST</c> posts, since it will trigger the underlying servlet 075 * API to parse the body content as key-value pairs resulting in empty content. 076 * 077 * <p> 078 * The {@link Query @Query} annotation can be used to retrieve a URL parameter in the URL string without triggering the 079 * servlet to drain the body content. 080 * 081 * <h5 class='topic'>Arguments and argument-types of client-side @RemoteResource-annotated interfaces</h5> 082 * <p> 083 * Annotation applied to Java method arguments of interface proxies to denote that they are FORM post parameters on the 084 * request. 085 * 086 * <h5 class='section'>See Also:</h5><ul> 087 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/FormData">@FormData</a> 088 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/Request">@Request</a> 089 * </ul> 090 * 091 * <h5 class='topic'>Methods and return types of server-side and client-side @Request-annotated interfaces</h5> 092 * <p> 093 * <h5 class='section'>See Also:</h5><ul> 094 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/Request">@Request</a> 095 * </ul> 096 * 097 * <div class='warn'> 098 * This annotation should not be combined with the {@link Content @Content} annotation or <c>RestRequest#getContent()</c> method 099 * for <c>application/x-www-form-urlencoded POST</c> posts, since it will trigger the underlying servlet 100 * API to parse the body content as key-value pairs resulting in empty content. 101 * <br>The {@link Query @Query} annotation can be used to retrieve a URL parameter in the URL string without triggering the 102 * servlet to drain the body content. 103 * </div> 104 * <div class='warn'> 105 * If using this annotation on a Spring bean, note that you are likely to encounter issues when using on parameterized 106 * types such as <code>List<MyBean></code>. This is due to the fact that Spring uses CGLIB to recompile classes 107 * at runtime, and CGLIB was written before generics were introduced into Java and is a virtually-unsupported library. 108 * Therefore, parameterized types will often be stripped from class definitions and replaced with unparameterized types 109 * (e.g. <code>List</code>). Under these circumstances, you are likely to get <code>ClassCastExceptions</code> 110 * when trying to access generalized <code>JsonMaps</code> as beans. The best solution to this issue is to either 111 * specify the parameter as a bean array (e.g. <code>MyBean[]</code>) or declare the method as final so that CGLIB 112 * will not try to recompile it. 113 * </div> 114 * 115 */ 116@Documented 117@Target({ PARAMETER, METHOD, TYPE, FIELD }) 118@Retention(RUNTIME) 119@Inherited 120public @interface FormData { 121 122 /** 123 * Default value for this parameter. 124 * 125 * @return The annotation value. 126 */ 127 String def() default ""; 128 129 /** 130 * Optional description for the exposed API. 131 * 132 * @return The annotation value. 133 * @since 9.2.0 134 */ 135 String[] description() default {}; 136 137 /** 138 * Short, concise summary of the exposed API. 139 * 140 * <p> 141 * Intended as a brief, single-line description suitable for AI/LLM consumption, compact documentation, 142 * or any context where brevity matters. See {@link Schema#summary()} 143 * for the canonical definition. 144 * 145 * @return The annotation value. 146 * @since 10.0.0 147 */ 148 String summary() default ""; 149 150 /** 151 * FORM parameter name. 152 * 153 * <p> 154 * The name of the parameter (required). 155 * 156 * <p> 157 * The value should be either a valid form parameter name, or <js>"*"</js> to represent multiple name/value pairs 158 * 159 * <p> 160 * A blank value (the default) has the following behavior: 161 * <ul class='spaced-list'> 162 * <li> 163 * If the data type is <c>NameValuePairs</c>, <c>Map</c>, or a bean, 164 * then it's the equivalent to <js>"*"</js> which will cause the value to be serialized as name/value pairs. 165 * 166 * <h5 class='figure'>Examples:</h5> 167 * <p class='bjava'> 168 * <jc>// When used on a REST method</jc> 169 * <ja>@RestPost</ja>(<js>"/addPet"</js>) 170 * <jk>public void</jk> addPet(<ja>@FormData</ja> JsonMap <jv>allFormDataParameters</jv>) {...} 171 * </p> 172 * <p class='bjava'> 173 * <jc>// When used on a remote method parameter</jc> 174 * <ja>@RemoteResource</ja>(path=<js>"/myproxy"</js>) 175 * <jk>public interface</jk> MyProxy { 176 * 177 * <jc>// Equivalent to @FormData("*")</jc> 178 * <ja>@RemotePost</ja>(<js>"/mymethod"</js>) 179 * String myProxyMethod1(<ja>@FormData</ja> Map<String,Object> <jv>allFormDataParameters</jv>); 180 * } 181 * </p> 182 * <p class='bjava'> 183 * <jc>// When used on a request bean method</jc> 184 * <jk>public interface</jk> MyRequest { 185 * 186 * <jc>// Equivalent to @FormData("*")</jc> 187 * <ja>@FormData</ja> 188 * Map<String,Object> getFoo(); 189 * } 190 * </p> 191 * </li> 192 * <li> 193 * If used on a request bean method, uses the bean property name. 194 * 195 * <h5 class='figure'>Example:</h5> 196 * <p class='bjava'> 197 * <jk>public interface</jk> MyRequest { 198 * 199 * <jc>// Equivalent to @FormData("foo")</jc> 200 * <ja>@FormData</ja> 201 * String getFoo(); 202 * } 203 * </p> 204 * </li> 205 * </ul> 206 * 207 * <h5 class='section'>Notes:</h5><ul> 208 * <li class='note'> 209 * The format is plain-text. 210 * </ul> 211 * 212 * @return The annotation value. 213 */ 214 String name() default ""; 215 216 /** 217 * <mk>schema</mk> field of the <a class='doclink' href='https://swagger.io/specification/v2#parameterObject'>Swagger Parameter Object</a>. 218 * 219 * <p> 220 * The schema defining the type used for parameter. 221 * 222 * <p> 223 * The {@link Schema @Schema} annotation can also be used standalone on the parameter or type. 224 * Values specified on this field override values specified on the type, and values specified on child types override values 225 * specified on parent types. 226 * 227 * <h5 class='section'>Used for:</h5> 228 * <ul class='spaced-list'> 229 * <li> 230 * Server-side schema-based parsing and parsing validation. 231 * <li> 232 * Server-side generated Swagger documentation. 233 * <li> 234 * Client-side schema-based serializing and serializing validation. 235 * </ul> 236 * 237 * @return The annotation value. 238 */ 239 Schema schema() default @Schema; 240 241 /** 242 * A synonym for {@link #name()}. 243 * 244 * <p> 245 * Allows you to use shortened notation if you're only specifying the name. 246 * 247 * <p> 248 * The following are completely equivalent ways of defining a form post entry: 249 * <p class='bjava'> 250 * <jk>public</jk> Order placeOrder(<ja>@FormData</ja>(name=<js>"petId"</js>) <jk>long</jk> <jv>petId</jv>) {...} 251 * </p> 252 * <p class='bjava'> 253 * <jk>public</jk> Order placeOrder(<ja>@FormData</ja>(<js>"petId"</js>) <jk>long</jk> <jv>petId</jv>) {...} 254 * </p> 255 * 256 * @return The annotation value. 257 */ 258 String value() default ""; 259}