001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.rest; 014 015import static org.apache.juneau.internal.ArrayUtils.*; 016import static org.apache.juneau.internal.StringUtils.*; 017 018import java.lang.reflect.*; 019import java.util.*; 020 021import javax.servlet.http.*; 022 023import org.apache.juneau.*; 024import org.apache.juneau.http.annotation.*; 025import org.apache.juneau.httppart.*; 026import org.apache.juneau.internal.*; 027import org.apache.juneau.json.*; 028import org.apache.juneau.oapi.*; 029import org.apache.juneau.parser.*; 030import org.apache.juneau.rest.exception.*; 031 032/** 033 * Represents the parsed form-data parameters in an HTTP request. 034 * 035 * <p> 036 * Similar in functionality to the {@link HttpServletRequest#getParameter(String)} except only looks in the body of the request, not parameters from 037 * the URL query string. 038 * <br>This can be useful in cases where you're using GET parameters on FORM POSTs, and you don't want the body of the request to be read. 039 * 040 * <p> 041 * Use of this object is incompatible with using any other methods that access the body of the request (since this object will 042 * consume the body). 043 * <br>Some examples: 044 * <ul> 045 * <li class='jm'>{@link RestRequest#getBody()} 046 * <li class='jm'>{@link RestRequest#getReader()} 047 * <li class='jm'>{@link RestRequest#getInputStream()} 048 * <li class='ja'>{@link FormData} 049 * </ul> 050 * 051 * <h5 class='section'>See Also:</h5> 052 * <ul> 053 * <li class='link'>{@doc juneau-rest-server.RestMethod.RequestFormData} 054 * </ul> 055 */ 056@SuppressWarnings("unchecked") 057public class RequestFormData extends LinkedHashMap<String,String[]> { 058 private static final long serialVersionUID = 1L; 059 060 private final RestRequest req; 061 private final HttpPartParser parser; 062 063 RequestFormData(RestRequest req, HttpPartParser parser) { 064 this.req = req; 065 this.parser = parser; 066 } 067 068 /** 069 * Adds default entries to these form-data parameters. 070 * 071 * <p> 072 * This includes the default form-data parameters defined on the resource and method levels. 073 * 074 * @param defaultEntries 075 * The default entries. 076 * <br>Can be <jk>null</jk>. 077 * @return This object (for method chaining). 078 */ 079 public RequestFormData addDefault(Map<String,Object> defaultEntries) { 080 if (defaultEntries != null) { 081 for (Map.Entry<String,Object> e : defaultEntries.entrySet()) { 082 String key = e.getKey(); 083 Object value = e.getValue(); 084 String[] v = get(key); 085 if (v == null || v.length == 0 || StringUtils.isEmpty(v[0])) 086 put(key, asStrings(value)); 087 } 088 } 089 return this; 090 } 091 092 /** 093 * Adds a default entries to these form-data parameters. 094 * 095 * <p> 096 * Similar to {@link #put(String, Object)} but doesn't override existing values. 097 * 098 * @param name 099 * The form-data parameter name. 100 * @param value 101 * The form-data parameter value. 102 * <br>Converted to a String using <code>toString()</code>. 103 * <br>Ignored if value is <jk>null</jk> or blank. 104 * @return This object (for method chaining). 105 */ 106 public RequestFormData addDefault(String name, Object value) { 107 return addDefault(Collections.singletonMap(name, value)); 108 } 109 110 /** 111 * Sets a request form-data parameter value. 112 * 113 * @param name The parameter name. 114 * @param value The parameter value. 115 */ 116 public void put(String name, Object value) { 117 super.put(name, asStrings(value)); 118 } 119 120 /** 121 * Returns a form-data parameter value. 122 * 123 * <p> 124 * Parameter lookup is case-insensitive (consistent with WAS, but differs from Tomcat). 125 * 126 * <h5 class='section'>Notes:</h5> 127 * <ul class='spaced-list'> 128 * <li> 129 * This method returns the raw unparsed value, and differs from calling 130 * <code>get(name, String.<jk>class</js>)</code> which will convert the value from UON 131 * notation: 132 * <ul> 133 * <li><js>"null"</js> => <jk>null</jk> 134 * <li><js>"'null'"</js> => <js>"null"</js> 135 * <li><js>"'foo bar'"</js> => <js>"foo bar"</js> 136 * <li><js>"foo~~bar"</js> => <js>"foo~bar"</js> 137 * </ul> 138 * </ul> 139 * 140 * @param name The form-data parameter name. 141 * @return The parameter value, or <jk>null</jk> if parameter does not exist. 142 */ 143 public String getString(String name) { 144 String[] v = get(name); 145 if (v == null || v.length == 0) 146 return null; 147 148 // Fix for behavior difference between Tomcat and WAS. 149 // getParameter("foo") on "&foo" in Tomcat returns "". 150 // getParameter("foo") on "&foo" in WAS returns null. 151 if (v.length == 1 && v[0] == null) 152 return ""; 153 154 return v[0]; 155 } 156 157 /** 158 * Same as {@link #getString(String)} except returns a default value if <jk>null</jk> or empty. 159 * 160 * @param name The form-data parameter name. 161 * @param def The default value. 162 * @return The parameter value, or the default value if parameter does not exist or is <jk>null</jk> or empty. 163 */ 164 public String getString(String name, String def) { 165 String s = getString(name); 166 return StringUtils.isEmpty(s) ? def : s; 167 } 168 169 /** 170 * Same as {@link #getString(String)} but converts the value to an integer. 171 * 172 * @param name The form-data parameter name. 173 * @return The parameter value, or <code>0</code> if parameter does not exist or is <jk>null</jk> or empty. 174 */ 175 public int getInt(String name) { 176 return getInt(name, 0); 177 } 178 179 /** 180 * Same as {@link #getString(String,String)} but converts the value to an integer. 181 * 182 * @param name The form-data parameter name. 183 * @param def The default value. 184 * @return The parameter value, or the default value if parameter does not exist or is <jk>null</jk> or empty. 185 */ 186 public int getInt(String name, int def) { 187 String s = getString(name); 188 return StringUtils.isEmpty(s) ? def : Integer.parseInt(s); 189 } 190 191 /** 192 * Same as {@link #getString(String)} but converts the value to a boolean. 193 * 194 * @param name The form-data parameter name. 195 * @return The parameter value, or <jk>false</jk> if parameter does not exist or is <jk>null</jk> or empty. 196 */ 197 public boolean getBoolean(String name) { 198 return getBoolean(name, false); 199 } 200 201 /** 202 * Same as {@link #getString(String,String)} but converts the value to a boolean. 203 * 204 * @param name The form-data parameter name. 205 * @param def The default value. 206 * @return The parameter value, or the default value if parameter does not exist or is <jk>null</jk> or empty. 207 */ 208 public boolean getBoolean(String name, boolean def) { 209 String s = getString(name); 210 return StringUtils.isEmpty(s) ? def : Boolean.parseBoolean(s); 211 } 212 213 /** 214 * Returns the specified form-data parameter value converted to a POJO using the {@link HttpPartParser} registered with the resource. 215 * 216 * <h5 class='section'>Examples:</h5> 217 * <p class='bcode w800'> 218 * <jc>// Parse into an integer.</jc> 219 * <jk>int</jk> myparam = formData.get(<js>"myparam"</js>, <jk>int</jk>.<jk>class</jk>); 220 * 221 * <jc>// Parse into an int array.</jc> 222 * <jk>int</jk>[] myparam = formData.get(<js>"myparam"</js>, <jk>int</jk>[].<jk>class</jk>); 223 224 * <jc>// Parse into a bean.</jc> 225 * MyBean myparam = formData.get(<js>"myparam"</js>, MyBean.<jk>class</jk>); 226 * 227 * <jc>// Parse into a linked-list of objects.</jc> 228 * List myparam = formData.get(<js>"myparam"</js>, LinkedList.<jk>class</jk>); 229 * 230 * <jc>// Parse into a map of object keys/values.</jc> 231 * Map myparam = formData.get(<js>"myparam"</js>, TreeMap.<jk>class</jk>); 232 * </p> 233 * 234 * <h5 class='section'>See Also:</h5> 235 * <ul> 236 * <li class='jf'>{@link RestContext#REST_partParser} 237 * </ul> 238 * 239 * @param name The parameter name. 240 * @param type The class type to convert the parameter value to. 241 * @param <T> The class type to convert the parameter value to. 242 * @return The parameter value converted to the specified class type. 243 * @throws BadRequest Thrown if input could not be parsed. 244 * @throws InternalServerError Thrown if any other exception occurs. 245 */ 246 public <T> T get(String name, Class<T> type) throws BadRequest, InternalServerError { 247 return getInner(null, null, name, null, getClassMeta(type)); 248 } 249 250 /** 251 * Same as {@link #get(String, Object, Class)} but allows you to override the part parser. 252 * 253 * @param parser 254 * The parser to use for parsing the string value. 255 * <br>If <jk>null</jk>, uses the part parser defined on the resource/method. 256 * @param schema 257 * The schema object that defines the format of the input. 258 * <br>If <jk>null</jk>, defaults to the schema defined on the parser. 259 * <br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}. 260 * <br>Only used if parser is schema-aware (e.g. {@link OpenApiParser}). 261 * @param name The parameter name. 262 * @param type The class type to convert the parameter value to. 263 * @param <T> The class type to convert the parameter value to. 264 * @return The parameter value converted to the specified class type. 265 * @throws BadRequest Thrown if input could not be parsed or fails schema validation. 266 * @throws InternalServerError Thrown if any other exception occurs. 267 */ 268 public <T> T get(HttpPartParser parser, HttpPartSchema schema, String name, Class<T> type) throws BadRequest, InternalServerError { 269 return getInner(parser, schema, name, null, getClassMeta(type)); 270 } 271 272 /** 273 * Same as {@link #get(String, Class)} except returns a default value if not specified. 274 * 275 * @param name The parameter name. 276 * @param def The default value if the parameter was not specified or is <jk>null</jk>. 277 * @param type The class type to convert the parameter value to. 278 * @param <T> The class type to convert the parameter value to. 279 * @return The parameter value converted to the specified class type. 280 * @throws BadRequest Thrown if input could not be parsed. 281 * @throws InternalServerError Thrown if any other exception occurs. 282 */ 283 public <T> T get(String name, T def, Class<T> type) throws BadRequest, InternalServerError { 284 return getInner(null, null, name, def, getClassMeta(type)); 285 } 286 287 /** 288 * Same as {@link #get(String, Object, Class)} but allows you to override the part parser. 289 * 290 * @param parser 291 * The parser to use for parsing the string value. 292 * <br>If <jk>null</jk>, uses the part parser defined on the resource/method. 293 * @param schema 294 * The schema object that defines the format of the input. 295 * <br>If <jk>null</jk>, defaults to the schema defined on the parser. 296 * <br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}. 297 * <br>Only used if parser is schema-aware (e.g. {@link OpenApiParser}). 298 * @param name The parameter name. 299 * @param def The default value if the parameter was not specified or is <jk>null</jk>. 300 * @param type The class type to convert the parameter value to. 301 * @param <T> The class type to convert the parameter value to. 302 * @return The parameter value converted to the specified class type. 303 * @throws BadRequest Thrown if input could not be parsed or fails schema validation. 304 * @throws InternalServerError Thrown if any other exception occurs. 305 */ 306 public <T> T get(HttpPartParser parser, HttpPartSchema schema, String name, T def, Class<T> type) throws BadRequest, InternalServerError { 307 return getInner(parser, schema, name, def, getClassMeta(type)); 308 } 309 310 /** 311 * Same as {@link #get(String, Class)} except for use on multi-part parameters 312 * (e.g. <js>"key=1&key=2&key=3"</js> instead of <js>"key=@(1,2,3)"</js>) 313 * 314 * <p> 315 * This method must only be called when parsing into classes of type Collection or array. 316 * 317 * @param name The parameter name. 318 * @param type The class type to convert the parameter value to. 319 * @return The parameter value converted to the specified class type. 320 * @throws BadRequest Thrown if input could not be parsed. 321 * @throws InternalServerError Thrown if any other exception occurs. 322 */ 323 public <T> T getAll(String name, Class<T> type) throws BadRequest, InternalServerError { 324 return getAllInner(null, null, name, null, getClassMeta(type)); 325 } 326 327 /** 328 * Same as {@link #getAll(String, Class)} but allows you to override the part parser. 329 * 330 * <p> 331 * This method must only be called when parsing into classes of type Collection or array. 332 * 333 * @param parser 334 * The parser to use for parsing the string value. 335 * <br>If <jk>null</jk>, uses the part parser defined on the resource/method. 336 * @param schema 337 * The schema object that defines the format of the input. 338 * <br>If <jk>null</jk>, defaults to the schema defined on the parser. 339 * <br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}. 340 * <br>Only used if parser is schema-aware (e.g. {@link OpenApiParser}). 341 * @param name The parameter name. 342 * @param type The class type to convert the parameter value to. 343 * @return The parameter value converted to the specified class type. 344 * @throws BadRequest Thrown if input could not be parsed or fails schema validation. 345 * @throws InternalServerError Thrown if any other exception occurs. 346 */ 347 public <T> T getAll(HttpPartParser parser, HttpPartSchema schema, String name, Class<T> type) throws BadRequest, InternalServerError { 348 return getAllInner(parser, schema, name, null, getClassMeta(type)); 349 } 350 351 /** 352 * Returns the specified form-data parameter value converted to a POJO using the {@link HttpPartParser} registered with the resource. 353 * 354 * <p> 355 * Similar to {@link #get(String,Class)} but allows for complex collections of POJOs to be created. 356 * 357 * <h5 class='section'>Examples:</h5> 358 * <p class='bcode w800'> 359 * <jc>// Parse into a linked-list of strings.</jc> 360 * List<String> myparam = formData.get(<js>"myparam"</js>, LinkedList.<jk>class</jk>, String.<jk>class</jk>); 361 * 362 * <jc>// Parse into a linked-list of linked-lists of strings.</jc> 363 * List<List<String>> myparam = formData.get(<js>"myparam"</js>, LinkedList.<jk>class</jk>, LinkedList.<jk>class</jk>, String.<jk>class</jk>); 364 * 365 * <jc>// Parse into a map of string keys/values.</jc> 366 * Map<String,String> myparam = formData.getr(<js>"myparam"</js>, TreeMap.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>); 367 * 368 * <jc>// Parse into a map containing string keys and values of lists containing beans.</jc> 369 * Map<String,List<MyBean>> myparam = formData.get(<js>"myparam"</js>, TreeMap.<jk>class</jk>, String.<jk>class</jk>, List.<jk>class</jk>, MyBean.<jk>class</jk>); 370 * </p> 371 * 372 * <h5 class='section'>Notes:</h5> 373 * <ul class='spaced-list'> 374 * <li> 375 * <code>Collections</code> must be followed by zero or one parameter representing the value type. 376 * <li> 377 * <code>Maps</code> must be followed by zero or two parameters representing the key and value types. 378 * </ul> 379 * 380 * <h5 class='section'>See Also:</h5> 381 * <ul> 382 * <li class='jf'>{@link RestContext#REST_partParser} 383 * </ul> 384 * 385 * @param name The parameter name. 386 * @param type 387 * The type of object to create. 388 * <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType} 389 * @param args 390 * The type arguments of the class if it's a collection or map. 391 * <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType} 392 * <br>Ignored if the main type is not a map or collection. 393 * @return The parameter value converted to the specified class type. 394 * @throws BadRequest Thrown if input could not be parsed. 395 * @throws InternalServerError Thrown if any other exception occurs. 396 */ 397 public <T> T get(String name, Type type, Type...args) throws BadRequest, InternalServerError { 398 return getInner(null, null, name, null, this.<T>getClassMeta(type, args)); 399 } 400 401 /** 402 * Same as {@link #get(String, Type, Type...)} but allows you to override the part parser. 403 * 404 * @param parser 405 * The parser to use for parsing the string value. 406 * <br>If <jk>null</jk>, uses the part parser defined on the resource/method. 407 * @param schema 408 * The schema object that defines the format of the input. 409 * <br>If <jk>null</jk>, defaults to the schema defined on the parser. 410 * <br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}. 411 * <br>Only used if parser is schema-aware (e.g. {@link OpenApiParser}). 412 * @param name The parameter name. 413 * @param type 414 * The type of object to create. 415 * <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType} 416 * @param args 417 * The type arguments of the class if it's a collection or map. 418 * <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType} 419 * <br>Ignored if the main type is not a map or collection. 420 * @return The parameter value converted to the specified class type. 421 * @throws BadRequest Thrown if input could not be parsed or fails schema validation. 422 * @throws InternalServerError Thrown if any other exception occurs. 423 */ 424 public <T> T get(HttpPartParser parser, HttpPartSchema schema, String name, Type type, Type...args) throws BadRequest, InternalServerError { 425 return getInner(parser, schema, name, null, this.<T>getClassMeta(type, args)); 426 } 427 428 /** 429 * Same as {@link #get(String, Class)} except returns a default value if not found. 430 * 431 * @param name The parameter name. 432 * @param type 433 * The type of object to create. 434 * <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType} 435 * @param args 436 * The type arguments of the class if it's a collection or map. 437 * <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType} 438 * <br>Ignored if the main type is not a map or collection. 439 * @param def The default value if the parameter was not specified or is <jk>null</jk>. 440 * @param <T> The class type to convert the parameter value to. 441 * @return The parameter value converted to the specified class type. 442 * @throws BadRequest Thrown if input could not be parsed. 443 * @throws InternalServerError Thrown if any other exception occurs. 444 */ 445 public <T> T get(String name, T def, Type type, Type...args) throws BadRequest, InternalServerError { 446 return getInner(null, null, name, def, this.<T>getClassMeta(type, args)); 447 } 448 449 /** 450 * Same as {@link #get(String, Object, Type, Type...)} but allows you to override the part parser. 451 * 452 * @param parser 453 * The parser to use for parsing the string value. 454 * <br>If <jk>null</jk>, uses the part parser defined on the resource/method. 455 * @param schema 456 * The schema object that defines the format of the input. 457 * <br>If <jk>null</jk>, defaults to the schema defined on the parser. 458 * <br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}. 459 * <br>Only used if parser is schema-aware (e.g. {@link OpenApiParser}). 460 * @param name The parameter name. 461 * @param type 462 * The type of object to create. 463 * <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType} 464 * @param args 465 * The type arguments of the class if it's a collection or map. 466 * <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType} 467 * <br>Ignored if the main type is not a map or collection. 468 * @param def The default value if the parameter was not specified or is <jk>null</jk>. 469 * @param <T> The class type to convert the parameter value to. 470 * @return The parameter value converted to the specified class type. 471 * @throws BadRequest Thrown if input could not be parsed or fails schema validation. 472 * @throws InternalServerError Thrown if any other exception occurs. 473 */ 474 public <T> T get(HttpPartParser parser, HttpPartSchema schema, String name, T def, Type type, Type...args) throws BadRequest, InternalServerError { 475 return getInner(parser, schema, name, def, this.<T>getClassMeta(type, args)); 476 } 477 478 /** 479 * Same as {@link #get(String, Type, Type...)} except for use on multi-part parameters 480 * (e.g. <js>"key=1&key=2&key=3"</js> instead of <js>"key=@(1,2,3)"</js>) 481 * 482 * <p> 483 * This method must only be called when parsing into classes of type Collection or array. 484 * 485 * @param name The parameter name. 486 * @param type 487 * The type of object to create. 488 * <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType} 489 * @param args 490 * The type arguments of the class if it's a collection or map. 491 * <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType} 492 * <br>Ignored if the main type is not a map or collection. 493 * @return The parameter value converted to the specified class type. 494 * @throws BadRequest Thrown if input could not be parsed. 495 * @throws InternalServerError Thrown if any other exception occurs. 496 */ 497 public <T> T getAll(String name, Type type, Type...args) throws BadRequest, InternalServerError { 498 return getAllInner(null, null, name, null, this.<T>getClassMeta(type, args)); 499 } 500 501 /** 502 * Same as {@link #getAll(String, Type, Type...)} but allows you to override the part parser. 503 * 504 * @param parser 505 * The parser to use for parsing the string value. 506 * <br>If <jk>null</jk>, uses the part parser defined on the resource/method. 507 * @param schema 508 * The schema object that defines the format of the input. 509 * <br>If <jk>null</jk>, defaults to the schema defined on the parser. 510 * <br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}. 511 * <br>Only used if parser is schema-aware (e.g. {@link OpenApiParser}). 512 * @param name The parameter name. 513 * @param type 514 * The type of object to create. 515 * <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType} 516 * @param args 517 * The type arguments of the class if it's a collection or map. 518 * <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType} 519 * <br>Ignored if the main type is not a map or collection. 520 * @return The parameter value converted to the specified class type. 521 * @throws BadRequest Thrown if input could not be parsed or fails schema validation. 522 * @throws InternalServerError Thrown if any other exception occurs. 523 */ 524 public <T> T getAll(HttpPartParser parser, HttpPartSchema schema, String name, Type type, Type...args) throws BadRequest, InternalServerError { 525 return getAllInner(parser, schema, name, null, this.<T>getClassMeta(type, args)); 526 } 527 528 /* Workhorse method */ 529 private <T> T getInner(HttpPartParser parser, HttpPartSchema schema, String name, T def, ClassMeta<T> cm) throws BadRequest, InternalServerError { 530 try { 531 if (cm.isMapOrBean() && isOneOf(name, "*", "")) { 532 ObjectMap m = new ObjectMap(); 533 for (Map.Entry<String,String[]> e : this.entrySet()) { 534 String k = e.getKey(); 535 HttpPartSchema pschema = schema == null ? null : schema.getProperty(k); 536 ClassMeta<?> cm2 = cm.getValueType(); 537 if (cm.getValueType().isCollectionOrArray()) 538 m.put(k, getAllInner(parser, pschema, k, null, cm2)); 539 else 540 m.put(k, getInner(parser, pschema, k, null, cm2)); 541 } 542 return req.getBeanSession().convertToType(m, cm); 543 } 544 T t = parse(parser, schema, getString(name), cm); 545 return (t == null ? def : t); 546 } catch (SchemaValidationException e) { 547 throw new BadRequest(e, "Validation failed on form-data parameter ''{0}''. ", name); 548 } catch (ParseException e) { 549 throw new BadRequest(e, "Could not parse form-data parameter ''{0}''.", name) ; 550 } catch (Exception e) { 551 throw new InternalServerError(e, "Could not parse form-data parameter ''{0}''.", name) ; 552 } 553 } 554 555 /* Workhorse method */ 556 @SuppressWarnings("rawtypes") 557 <T> T getAllInner(HttpPartParser parser, HttpPartSchema schema, String name, T def, ClassMeta<T> cm) throws BadRequest, InternalServerError { 558 String[] p = get(name); 559 if (p == null) 560 return def; 561 if (schema == null) 562 schema = HttpPartSchema.DEFAULT; 563 try { 564 if (cm.isArray()) { 565 List c = new ArrayList(); 566 for (int i = 0; i < p.length; i++) 567 c.add(parse(parser, schema.getItems(), p[i], cm.getElementType())); 568 return (T)toArray(c, cm.getElementType().getInnerClass()); 569 } else if (cm.isCollection()) { 570 Collection c = (Collection)(cm.canCreateNewInstance() ? cm.newInstance() : new ObjectList()); 571 for (int i = 0; i < p.length; i++) 572 c.add(parse(parser, schema.getItems(), p[i], cm.getElementType())); 573 return (T)c; 574 } 575 } catch (SchemaValidationException e) { 576 throw new BadRequest(e, "Validation failed on form-data parameter ''{0}''. ", name); 577 } catch (ParseException e) { 578 throw new BadRequest(e, "Could not parse form-data parameter ''{0}''.", name) ; 579 } catch (Exception e) { 580 throw new InternalServerError(e, "Could not parse form-data parameter ''{0}''.", name) ; 581 } 582 throw new InternalServerError("Invalid call to getParameters(String, ClassMeta). Class type must be a Collection or array."); 583 } 584 585 private <T> T parse(HttpPartParser parser, HttpPartSchema schema, String val, ClassMeta<T> c) throws SchemaValidationException, ParseException { 586 if (parser == null) 587 parser = this.parser; 588 return parser.createPartSession(req.getParserSessionArgs()).parse(HttpPartType.FORMDATA, schema, val, c); 589 } 590 591 /** 592 * Converts the form-data parameters to a readable string. 593 * 594 * @param sorted Sort the form-data parameters by name. 595 * @return A JSON string containing the contents of the form-data parameters. 596 */ 597 public String toString(boolean sorted) { 598 Map<String,Object> m = (sorted ? new TreeMap<String,Object>() : new LinkedHashMap<String,Object>()); 599 for (Map.Entry<String,String[]> e : this.entrySet()) { 600 String[] v = e.getValue(); 601 if (v != null) 602 m.put(e.getKey(), v.length == 1 ? v[0] : v); 603 } 604 return SimpleJsonSerializer.DEFAULT.toString(m); 605 } 606 607 @Override /* Object */ 608 public String toString() { 609 return toString(false); 610 } 611 612 //----------------------------------------------------------------------------------------------------------------- 613 // Helper methods 614 //----------------------------------------------------------------------------------------------------------------- 615 616 private <T> ClassMeta<T> getClassMeta(Type type, Type...args) { 617 return req.getBeanSession().getClassMeta(type, args); 618 } 619 620 private <T> ClassMeta<T> getClassMeta(Class<T> type) { 621 return req.getBeanSession().getClassMeta(type); 622 } 623}