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