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.lang.reflect.Type;
020import java.util.*;
021
022import javax.servlet.http.*;
023
024import org.apache.juneau.*;
025import org.apache.juneau.collections.*;
026import org.apache.juneau.http.annotation.*;
027import org.apache.juneau.httppart.*;
028import org.apache.juneau.internal.*;
029import org.apache.juneau.json.*;
030import org.apache.juneau.oapi.*;
031import org.apache.juneau.parser.*;
032import org.apache.juneau.http.exception.*;
033
034/**
035 * Represents the parsed form-data parameters in an HTTP request.
036 *
037 * <p>
038 * Similar in functionality to the {@link HttpServletRequest#getParameter(String)} except only looks in the body of the request, not parameters from
039 * the URL query string.
040 * <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.
041 *
042 * <p>
043 * Use of this object is incompatible with using any other methods that access the body of the request (since this object will
044 * consume the body).
045 * <br>Some examples:
046 * <ul>
047 *    <li class='jm'>{@link RestRequest#getBody()}
048 *    <li class='jm'>{@link RestRequest#getReader()}
049 *    <li class='jm'>{@link RestRequest#getInputStream()}
050 *    <li class='ja'>{@link FormData}
051 * </ul>
052 *
053 * <ul class='seealso'>
054 *    <li class='link'>{@doc RestmRequestFormData}
055 * </ul>
056 */
057@SuppressWarnings("unchecked")
058public class RequestFormData extends LinkedHashMap<String,String[]> {
059   private static final long serialVersionUID = 1L;
060
061   private final RestRequest req;
062   private final HttpPartParserSession parser;
063
064   RequestFormData(RestRequest req, HttpPartParserSession parser) {
065      this.req = req;
066      this.parser = parser;
067   }
068
069   /**
070    * Adds default entries to these form-data parameters.
071    *
072    * <p>
073    * This includes the default form-data parameters defined on the resource and method levels.
074    *
075    * @param defaultEntries
076    *    The default entries.
077    *    <br>Can be <jk>null</jk>.
078    * @return This object (for method chaining).
079    */
080   public RequestFormData addDefault(Map<String,Object> defaultEntries) {
081      if (defaultEntries != null) {
082         for (Map.Entry<String,Object> e : defaultEntries.entrySet()) {
083            String key = e.getKey();
084            Object value = e.getValue();
085            String[] v = get(key);
086            if (v == null || v.length == 0 || StringUtils.isEmpty(v[0]))
087               put(key, stringifyAll(value));
088         }
089      }
090      return this;
091   }
092
093   /**
094    * Adds a default entries to these form-data parameters.
095    *
096    * <p>
097    * Similar to {@link #put(String, Object)} but doesn't override existing values.
098    *
099    * @param name
100    *    The form-data parameter name.
101    * @param value
102    *    The form-data parameter value.
103    *    <br>Converted to a String using <c>toString()</c>.
104    *    <br>Ignored if value is <jk>null</jk> or blank.
105    * @return This object (for method chaining).
106    */
107   public RequestFormData addDefault(String name, Object value) {
108      return addDefault(Collections.singletonMap(name, value));
109   }
110
111   /**
112    * Sets a request form-data parameter value.
113    *
114    * @param name The parameter name.
115    * @param value The parameter value.
116    */
117   public void put(String name, Object value) {
118      super.put(name, stringifyAll(value));
119   }
120
121   /**
122    * Returns a form-data parameter value.
123    *
124    * <ul class='notes'>
125    *    <li>
126    *       Parameter lookup is case-insensitive (consistent with WAS, but differs from Tomcat).
127    *    <li>
128    *       This method returns the raw unparsed value, and differs from calling
129    *       <code>get(name, String.<jk>class</jk>)</code> which uses the {@link HttpPartParser} for parsing the value.
130    * </ul>
131    *
132    * @param name The form-data parameter name.
133    * @return The parameter value, or <jk>null</jk> if parameter does not exist.
134    */
135   public String getString(String name) {
136      String[] v = get(name);
137      if (v == null || v.length == 0)
138         return null;
139
140      // Fix for behavior difference between Tomcat and WAS.
141      // getParameter("foo") on "&foo" in Tomcat returns "".
142      // getParameter("foo") on "&foo" in WAS returns null.
143      if (v.length == 1 && v[0] == null)
144         return "";
145
146      return v[0];
147   }
148
149   /**
150    * Returns a form-data parameter value.
151    *
152    * <ul class='notes'>
153    *    <li>
154    *       Parameter lookup is case-insensitive (consistent with WAS, but differs from Tomcat).
155    *    <li>
156    *       This method returns the raw unparsed value, and differs from calling
157    *       <code>get(name, String.<jk>class</jk>)</code> which uses the {@link HttpPartParser} for parsing the value.
158    * </ul>
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    * Returns a form-data parameter value as an integer.
171    *
172    * <ul class='notes'>
173    *    <li>
174    *       Parameter lookup is case-insensitive (consistent with WAS, but differs from Tomcat).
175    *    <li>
176    *       This method returns the raw unparsed value, and differs from calling
177    *       <code>get(name, Integer.<jk>class</jk>)</code> which uses the {@link HttpPartParser} for parsing the value.
178    * </ul>
179    *
180    * @param name The form-data parameter name.
181    * @return The parameter value, or <c>0</c> if parameter does not exist or is <jk>null</jk> or empty.
182    */
183   public int getInt(String name) {
184      return getInt(name, 0);
185   }
186
187   /**
188    * Returns a form-data parameter value as an integer.
189    *
190    * <ul class='notes'>
191    *    <li>
192    *       Parameter lookup is case-insensitive (consistent with WAS, but differs from Tomcat).
193    *    <li>
194    *       This method returns the raw unparsed value, and differs from calling
195    *       <code>get(name, Integer.<jk>class</jk>)</code> which uses the {@link HttpPartParser} for parsing the value.
196    * </ul>
197    *
198    * @param name The form-data parameter name.
199    * @param def The default value.
200    * @return The parameter value, or the default value if parameter does not exist or is <jk>null</jk> or empty.
201    */
202   public int getInt(String name, int def) {
203      String s = getString(name);
204      return StringUtils.isEmpty(s) ? def : Integer.parseInt(s);
205   }
206
207   /**
208    * Returns a form-data parameter value as a boolean.
209    *
210    * <ul class='notes'>
211    *    <li>
212    *       Parameter lookup is case-insensitive (consistent with WAS, but differs from Tomcat).
213    *    <li>
214    *       This method returns the raw unparsed value, and differs from calling
215    *       <code>get(name, Boolean.<jk>class</jk>)</code> which uses the {@link HttpPartParser} for parsing the value.
216    * </ul>
217    *
218    * @param name The form-data parameter name.
219    * @return The parameter value, or <jk>false</jk> if parameter does not exist or is <jk>null</jk> or empty.
220    */
221   public boolean getBoolean(String name) {
222      return getBoolean(name, false);
223   }
224
225   /**
226    * Returns a form-data parameter value as a boolean.
227    *
228    * <ul class='notes'>
229    *    <li>
230    *       Parameter lookup is case-insensitive (consistent with WAS, but differs from Tomcat).
231    *    <li>
232    *       This method returns the raw unparsed value, and differs from calling
233    *       <code>get(name, Boolean.<jk>class</jk>)</code> which uses the {@link HttpPartParser} for parsing the value.
234    * </ul>
235    *
236    * @param name The form-data parameter name.
237    * @param def The default value.
238    * @return The parameter value, or the default value if parameter does not exist or is <jk>null</jk> or empty.
239    */
240   public boolean getBoolean(String name, boolean def) {
241      String s = getString(name);
242      return StringUtils.isEmpty(s) ? def : Boolean.parseBoolean(s);
243   }
244
245   /**
246    * Returns the specified form-data parameter value converted to a POJO using the {@link HttpPartParser} registered with the resource.
247    *
248    * <h5 class='section'>Examples:</h5>
249    * <p class='bcode w800'>
250    *    <jc>// Parse into an integer.</jc>
251    *    <jk>int</jk> myparam = formData.get(<js>"myparam"</js>, <jk>int</jk>.<jk>class</jk>);
252    *
253    *    <jc>// Parse into an int array.</jc>
254    *    <jk>int</jk>[] myparam = formData.get(<js>"myparam"</js>, <jk>int</jk>[].<jk>class</jk>);
255
256    *    <jc>// Parse into a bean.</jc>
257    *    MyBean myparam = formData.get(<js>"myparam"</js>, MyBean.<jk>class</jk>);
258    *
259    *    <jc>// Parse into a linked-list of objects.</jc>
260    *    List myparam = formData.get(<js>"myparam"</js>, LinkedList.<jk>class</jk>);
261    *
262    *    <jc>// Parse into a map of object keys/values.</jc>
263    *    Map myparam = formData.get(<js>"myparam"</js>, TreeMap.<jk>class</jk>);
264    * </p>
265    *
266    * <ul class='seealso'>
267    *    <li class='jf'>{@link RestContext#REST_partParser}
268    * </ul>
269    *
270    * @param name The parameter name.
271    * @param type The class type to convert the parameter value to.
272    * @param <T> The class type to convert the parameter value to.
273    * @return The parameter value converted to the specified class type.
274    * @throws BadRequest Thrown if input could not be parsed.
275    * @throws InternalServerError Thrown if any other exception occurs.
276    */
277   public <T> T get(String name, Class<T> type) throws BadRequest, InternalServerError {
278      return getInner(null, null, name, null, getClassMeta(type));
279   }
280
281   /**
282    * Returns the specified form-data parameter value converted to a POJO using the {@link HttpPartParser} registered with the resource.
283    *
284    * <h5 class='section'>Examples:</h5>
285    * <p class='bcode w800'>
286    *    <jc>// Pipe-delimited list of comma-delimited numbers</jc>
287    *    HttpPartSchema schema = HttpPartSchema.<jsm>create</jsm>()
288    *       .items(
289    *          HttpPartSchema.<jsm>create</jsm>()
290    *          .collectionFormat(<js>"pipes"</js>)
291    *          .items(
292    *             HttpPartSchema.<jsm>create</jsm>()
293    *             .collectionFormat(<js>"csv"</js>)
294    *             .type(<js>"integer"</js>)
295    *             .format(<js>"int64"</js>)
296    *             .minimum(<js>"0"</js>)
297    *             .maximum(<js>"100"</js>)
298    *             .minLength(1)
299    *             .maxLength=(10)
300    *          )
301    *       )
302    *       .build();
303    *
304    *    <jc>// Parse into a 2d long array.</jc>
305    *    <jk>long</jk>[][] myparams = formData.get(schema, <js>"myparam"</js>, <jk>long</jk>[][].<jk>class</jk>);
306    * </p>
307    *
308    * <ul class='seealso'>
309    *    <li class='jf'>{@link RestContext#REST_partParser}
310    * </ul>
311    *
312    * @param schema
313    *    The schema object that defines the format of the input.
314    *    <br>If <jk>null</jk>, defaults to the schema defined on the parser.
315    *    <br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.
316    *    <br>Only used if parser is schema-aware (e.g. {@link OpenApiParser}).
317    * @param name The parameter name.
318    * @param type The class type to convert the parameter value to.
319    * @param <T> The class type to convert the parameter value to.
320    * @return The parameter value converted to the specified class type.
321    * @throws BadRequest Thrown if input could not be parsed.
322    * @throws InternalServerError Thrown if any other exception occurs.
323    */
324   public <T> T get(HttpPartSchema schema, String name, Class<T> type) throws BadRequest, InternalServerError {
325      return getInner(null, schema, name, null, getClassMeta(type));
326   }
327
328   /**
329    * Returns the specified form-data parameter value converted to a POJO using the specified {@link HttpPartParser}.
330    *
331    * <h5 class='section'>Examples:</h5>
332    * <p class='bcode w800'>
333    *    <jc>// Pipe-delimited list of comma-delimited numbers</jc>
334    *    HttpPartSchema schema = HttpPartSchema.<jsm>create</jsm>()
335    *       .items(
336    *          HttpPartSchema.<jsm>create</jsm>()
337    *          .collectionFormat(<js>"pipes"</js>)
338    *          .items(
339    *             HttpPartSchema.<jsm>create</jsm>()
340    *             .collectionFormat(<js>"csv"</js>)
341    *             .type(<js>"integer"</js>)
342    *             .format(<js>"int64"</js>)
343    *             .minimum(<js>"0"</js>)
344    *             .maximum(<js>"100"</js>)
345    *             .minLength(1)
346    *             .maxLength=(10)
347    *          )
348    *       )
349    *       .build();
350    *
351    *  HttpPartParserSession parser = OpenApiParser.<jsf>DEFAULT</jsf>.createSession();
352    *
353    *    <jc>// Parse into a 2d long array.</jc>
354    *    <jk>long</jk>[][] myparams = formData.get(parser, schema, <js>"myparam"</js>, <jk>long</jk>[][].<jk>class</jk>);
355    * </p>
356    *
357    * <ul class='seealso'>
358    *    <li class='jf'>{@link RestContext#REST_partParser}
359    * </ul>
360    *
361    * @param parser
362    *    The parser to use for parsing the string value.
363    *    <br>If <jk>null</jk>, uses the part parser defined on the resource/method.
364    * @param schema
365    *    The schema object that defines the format of the input.
366    *    <br>If <jk>null</jk>, defaults to the schema defined on the parser.
367    *    <br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.
368    *    <br>Only used if parser is schema-aware (e.g. {@link OpenApiParser}).
369    * @param name The parameter name.
370    * @param type The class type to convert the parameter value to.
371    * @param <T> The class type to convert the parameter value to.
372    * @return The parameter value converted to the specified class type.
373    * @throws BadRequest Thrown if input could not be parsed or fails schema validation.
374    * @throws InternalServerError Thrown if any other exception occurs.
375    */
376   public <T> T get(HttpPartParserSession parser, HttpPartSchema schema, String name, Class<T> type) throws BadRequest, InternalServerError {
377      return getInner(parser, schema, name, null, getClassMeta(type));
378   }
379
380   /**
381    * Returns the specified form-data parameter value converted to a POJO using the {@link HttpPartParser} registered with the resource.
382    *
383    * <h5 class='section'>Examples:</h5>
384    * <p class='bcode w800'>
385    *    <jc>// Parse into an integer.</jc>
386    *    <jk>int</jk> myparam = formData.get(<js>"myparam"</js>, -1, <jk>int</jk>.<jk>class</jk>);
387    *
388    *    <jc>// Parse into an int array.</jc>
389    *    <jk>int</jk>[] myparam = formData.get(<js>"myparam"</js>, <jk>new int</jk>[0], <jk>int</jk>[].<jk>class</jk>);
390
391    *    <jc>// Parse into a bean.</jc>
392    *    MyBean myparam = formData.get(<js>"myparam"</js>, <jk>new</jk> MyBean(), MyBean.<jk>class</jk>);
393    *
394    *    <jc>// Parse into a linked-list of objects.</jc>
395    *    List myparam = formData.get(<js>"myparam"</js>, Collections.<jsm>emptyList</jsm>(), LinkedList.<jk>class</jk>);
396    *
397    *    <jc>// Parse into a map of object keys/values.</jc>
398    *    Map myparam = formData.get(<js>"myparam"</js>, Collections.<jsm>emptyMap</jsm>(), TreeMap.<jk>class</jk>);
399    * </p>
400    *
401    * <ul class='seealso'>
402    *    <li class='jf'>{@link RestContext#REST_partParser}
403    * </ul>
404    *
405    * @param name The parameter name.
406    * @param def The default value if the parameter was not specified or is <jk>null</jk>.
407    * @param type The class type to convert the parameter value to.
408    * @param <T> The class type to convert the parameter value to.
409    * @return The parameter value converted to the specified class type.
410    * @throws BadRequest Thrown if input could not be parsed.
411    * @throws InternalServerError Thrown if any other exception occurs.
412    */
413   public <T> T get(String name, T def, Class<T> type) throws BadRequest, InternalServerError {
414      return getInner(null, null, name, def, getClassMeta(type));
415   }
416
417   /**
418    * Returns the specified form-data parameter value converted to a POJO using the {@link HttpPartParser} registered with the resource.
419    *
420    * <h5 class='section'>Examples:</h5>
421    * <p class='bcode w800'>
422    *    <jc>// Pipe-delimited list of comma-delimited numbers</jc>
423    *    HttpPartSchema schema = HttpPartSchema.<jsm>create</jsm>()
424    *       .items(
425    *          HttpPartSchema.<jsm>create</jsm>()
426    *          .collectionFormat(<js>"pipes"</js>)
427    *          .items(
428    *             HttpPartSchema.<jsm>create</jsm>()
429    *             .collectionFormat(<js>"csv"</js>)
430    *             .type(<js>"integer"</js>)
431    *             .format(<js>"int64"</js>)
432    *             .minimum(<js>"0"</js>)
433    *             .maximum(<js>"100"</js>)
434    *             .minLength(1)
435    *             .maxLength=(10)
436    *          )
437    *       )
438    *       .build();
439    *
440    *    <jc>// Parse into a 2d long array.</jc>
441    *    <jk>long</jk>[][] myparams = formData.get(schema, <js>"myparam"</js>, <jk>new long</jk>[][0], <jk>long</jk>[][].<jk>class</jk>);
442    * </p>
443    *
444    * <ul class='seealso'>
445    *    <li class='jf'>{@link RestContext#REST_partParser}
446    * </ul>
447    *
448    * @param schema
449    *    The schema object that defines the format of the input.
450    *    <br>If <jk>null</jk>, defaults to the schema defined on the parser.
451    *    <br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.
452    *    <br>Only used if parser is schema-aware (e.g. {@link OpenApiParser}).
453    * @param name The parameter name.
454    * @param def The default value if the parameter was not specified or is <jk>null</jk>.
455    * @param type The class type to convert the parameter value to.
456    * @param <T> The class type to convert the parameter value to.
457    * @return The parameter value converted to the specified class type.
458    * @throws BadRequest Thrown if input could not be parsed.
459    * @throws InternalServerError Thrown if any other exception occurs.
460    */
461   public <T> T get(HttpPartSchema schema, String name, T def, Class<T> type) throws BadRequest, InternalServerError {
462      return getInner(null, schema, name, def, getClassMeta(type));
463   }
464
465   /**
466    * Returns the specified form-data parameter value converted to a POJO using the specified {@link HttpPartParser}.
467    *
468    * <h5 class='section'>Examples:</h5>
469    * <p class='bcode w800'>
470    *    <jc>// Pipe-delimited list of comma-delimited numbers</jc>
471    *    HttpPartSchema schema = HttpPartSchema.<jsm>create</jsm>()
472    *       .items(
473    *          HttpPartSchema.<jsm>create</jsm>()
474    *          .collectionFormat(<js>"pipes"</js>)
475    *          .items(
476    *             HttpPartSchema.<jsm>create</jsm>()
477    *             .collectionFormat(<js>"csv"</js>)
478    *             .type(<js>"integer"</js>)
479    *             .format(<js>"int64"</js>)
480    *             .minimum(<js>"0"</js>)
481    *             .maximum(<js>"100"</js>)
482    *             .minLength(1)
483    *             .maxLength=(10)
484    *          )
485    *       )
486    *       .build();
487    *
488    *  HttpPartParserSession parser = OpenApiParser.<jsf>DEFAULT</jsf>.createSession();
489    *
490    *    <jc>// Parse into a 2d long array.</jc>
491    *    <jk>long</jk>[][] myparams = formData.get(parser, schema, <js>"myparam"</js>, <jk>new long</jk>[][0], <jk>long</jk>[][].<jk>class</jk>);
492    * </p>
493    *
494    * <ul class='seealso'>
495    *    <li class='jf'>{@link RestContext#REST_partParser}
496    * </ul>
497    *
498    * @param parser
499    *    The parser to use for parsing the string value.
500    *    <br>If <jk>null</jk>, uses the part parser defined on the resource/method.
501    * @param schema
502    *    The schema object that defines the format of the input.
503    *    <br>If <jk>null</jk>, defaults to the schema defined on the parser.
504    *    <br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.
505    *    <br>Only used if parser is schema-aware (e.g. {@link OpenApiParser}).
506    * @param name The parameter name.
507    * @param def The default value if the parameter was not specified or is <jk>null</jk>.
508    * @param type The class type to convert the parameter value to.
509    * @param <T> The class type to convert the parameter value to.
510    * @return The parameter value converted to the specified class type.
511    * @throws BadRequest Thrown if input could not be parsed or fails schema validation.
512    * @throws InternalServerError Thrown if any other exception occurs.
513    */
514   public <T> T get(HttpPartParserSession parser, HttpPartSchema schema, String name, T def, Class<T> type) throws BadRequest, InternalServerError {
515      return getInner(parser, schema, name, def, getClassMeta(type));
516   }
517
518   /**
519    * Returns the specified form-data parameter value converted to a POJO using the {@link HttpPartParser} registered with the resource.
520    *
521    * <p>
522    * Similar to {@link #get(String,Class)} but allows for complex collections of POJOs to be created.
523    *
524    * <h5 class='section'>Examples:</h5>
525    * <p class='bcode w800'>
526    *    <jc>// Parse into a linked-list of strings.</jc>
527    *    List&lt;String&gt; myparam = formData.get(<js>"myparam"</js>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);
528    *
529    *    <jc>// Parse into a linked-list of linked-lists of strings.</jc>
530    *    List&lt;List&lt;String&gt;&gt; myparam = formData.get(<js>"myparam"</js>, LinkedList.<jk>class</jk>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);
531    *
532    *    <jc>// Parse into a map of string keys/values.</jc>
533    *    Map&lt;String,String&gt; myparam = formData.getr(<js>"myparam"</js>, TreeMap.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>);
534    *
535    *    <jc>// Parse into a map containing string keys and values of lists containing beans.</jc>
536    *    Map&lt;String,List&lt;MyBean&gt;&gt; myparam = formData.get(<js>"myparam"</js>, TreeMap.<jk>class</jk>, String.<jk>class</jk>, List.<jk>class</jk>, MyBean.<jk>class</jk>);
537    * </p>
538    *
539    * <ul class='notes'>
540    *    <li>
541    *       <c>Collections</c> must be followed by zero or one parameter representing the value type.
542    *    <li>
543    *       <c>Maps</c> must be followed by zero or two parameters representing the key and value types.
544    * </ul>
545    *
546    * <ul class='seealso'>
547    *    <li class='jf'>{@link RestContext#REST_partParser}
548    * </ul>
549    *
550    * @param name The parameter name.
551    * @param type
552    *    The type of object to create.
553    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
554    * @param args
555    *    The type arguments of the class if it's a collection or map.
556    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
557    *    <br>Ignored if the main type is not a map or collection.
558    * @return The parameter value converted to the specified class type.
559    * @throws BadRequest Thrown if input could not be parsed.
560    * @throws InternalServerError Thrown if any other exception occurs.
561    */
562   public <T> T get(String name, Type type, Type...args) throws BadRequest, InternalServerError {
563      return getInner(null, null, name, null, this.<T>getClassMeta(type, args));
564   }
565   
566   /**
567    * Same as {@link #get(String, Type, Type...)} but allows you to override the part parser.
568    *
569    * @param parser
570    *    The parser to use for parsing the string value.
571    *    <br>If <jk>null</jk>, uses the part parser defined on the resource/method.
572    * @param schema
573    *    The schema object that defines the format of the input.
574    *    <br>If <jk>null</jk>, defaults to the schema defined on the parser.
575    *    <br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.
576    *    <br>Only used if parser is schema-aware (e.g. {@link OpenApiParser}).
577    * @param name The parameter name.
578    * @param type
579    *    The type of object to create.
580    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
581    * @param args
582    *    The type arguments of the class if it's a collection or map.
583    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
584    *    <br>Ignored if the main type is not a map or collection.
585    * @return The parameter value converted to the specified class type.
586    * @throws BadRequest Thrown if input could not be parsed or fails schema validation.
587    * @throws InternalServerError Thrown if any other exception occurs.
588    */
589   public <T> T get(HttpPartParserSession parser, HttpPartSchema schema, String name, Type type, Type...args) throws BadRequest, InternalServerError {
590      return getInner(parser, schema, name, null, this.<T>getClassMeta(type, args));
591   }
592
593   /**
594    * Same as {@link #get(String, Class)} except returns a default value if not found.
595    *
596    * @param name The parameter name.
597    * @param type
598    *    The type of object to create.
599    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
600    * @param args
601    *    The type arguments of the class if it's a collection or map.
602    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
603    *    <br>Ignored if the main type is not a map or collection.
604    * @param def The default value if the parameter was not specified or is <jk>null</jk>.
605    * @param <T> The class type to convert the parameter value to.
606    * @return The parameter value converted to the specified class type.
607    * @throws BadRequest Thrown if input could not be parsed.
608    * @throws InternalServerError Thrown if any other exception occurs.
609    */
610   public <T> T get(String name, T def, Type type, Type...args) throws BadRequest, InternalServerError {
611      return getInner(null, null, name, def, this.<T>getClassMeta(type, args));
612   }
613
614   /**
615    * Same as {@link #get(String, Object, Type, Type...)} but allows you to override the part parser.
616    *
617    * @param parser
618    *    The parser to use for parsing the string value.
619    *    <br>If <jk>null</jk>, uses the part parser defined on the resource/method.
620    * @param schema
621    *    The schema object that defines the format of the input.
622    *    <br>If <jk>null</jk>, defaults to the schema defined on the parser.
623    *    <br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.
624    *    <br>Only used if parser is schema-aware (e.g. {@link OpenApiParser}).
625    * @param name The parameter name.
626    * @param type
627    *    The type of object to create.
628    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
629    * @param args
630    *    The type arguments of the class if it's a collection or map.
631    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
632    *    <br>Ignored if the main type is not a map or collection.
633    * @param def The default value if the parameter was not specified or is <jk>null</jk>.
634    * @param <T> The class type to convert the parameter value to.
635    * @return The parameter value converted to the specified class type.
636    * @throws BadRequest Thrown if input could not be parsed or fails schema validation.
637    * @throws InternalServerError Thrown if any other exception occurs.
638    */
639   public <T> T get(HttpPartParserSession parser, HttpPartSchema schema, String name, T def, Type type, Type...args) throws BadRequest, InternalServerError {
640      return getInner(parser, schema, name, def, this.<T>getClassMeta(type, args));
641   }
642
643   /**
644    * Returns the specified form-data parameter values converted POJO using the {@link HttpPartParser} registered with the resource.
645    *
646    * <p>
647    * Meant to be used on multi-part parameters (e.g. <js>"key=1&amp;key=2&amp;key=3"</js> instead of <js>"key=@(1,2,3)"</js>)
648    *
649    * <p>
650    * This method must only be called when parsing into classes of type Collection or array.
651    *
652    * <h5 class='section'>Examples:</h5>
653    * <p class='bcode w800'>
654    *    <jc>// Parse into multiple integers.</jc>
655    *    <jk>int</jk>[] myparam = formData.getAll(<js>"myparam"</js>, <jk>int</jk>[].<jk>class</jk>);
656    *
657    *    <jc>// Parse into multiple int arrays.</jc>
658    *    <jk>int</jk>[][] myparam = formData.getAll(<js>"myparam"</js>, <jk>int</jk>[][].<jk>class</jk>);
659
660    *    <jc>// Parse into multiple beans.</jc>
661    *    MyBean[] myparam = formData.getAll(<js>"myparam"</js>, MyBean[].<jk>class</jk>);
662    *
663    *    <jc>// Parse into multiple linked-lists of objects.</jc>
664    *    List[] myparam = formData.getAll(<js>"myparam"</js>, LinkedList[].<jk>class</jk>);
665    *
666    *    <jc>// Parse into multiple maps of object keys/values.</jc>
667    *    Map[] myparam = formData.getAll(<js>"myparam"</js>, TreeMap[].<jk>class</jk>);
668    * </p>
669    *
670    * <ul class='seealso'>
671    *    <li class='jf'>{@link RestContext#REST_partParser}
672    * </ul>
673    *
674    * @param name The parameter name.
675    * @param type The class type to convert the parameter value to.
676    * @return The parameter value converted to the specified class type.
677    * @throws BadRequest Thrown if input could not be parsed.
678    * @throws InternalServerError Thrown if any other exception occurs.
679    */
680   public <T> T getAll(String name, Class<T> type) throws BadRequest, InternalServerError {
681      return getAllInner(null, null, name, getClassMeta(type));
682   }
683
684   /**
685    * Returns the specified form-data parameter values converted to POJOs using the {@link HttpPartParser} registered with the resource.
686    *
687    * <p>
688    * Meant to be used on multi-part parameters (e.g. <js>"key=1&amp;key=2&amp;key=3"</js> instead of <js>"key=@(1,2,3)"</js>)
689    *
690    * <h5 class='section'>Examples:</h5>
691    * <p class='bcode w800'>
692    *    <jc>// Pipe-delimited list of comma-delimited numbers</jc>
693    *    HttpPartSchema schema = HttpPartSchema.<jsm>create</jsm>()
694    *       .items(
695    *          HttpPartSchema.<jsm>create</jsm>()
696    *          .collectionFormat(<js>"pipes"</js>)
697    *          .items(
698    *             HttpPartSchema.<jsm>create</jsm>()
699    *             .collectionFormat(<js>"csv"</js>)
700    *             .type(<js>"integer"</js>)
701    *             .format(<js>"int64"</js>)
702    *             .minimum(<js>"0"</js>)
703    *             .maximum(<js>"100"</js>)
704    *             .minLength(1)
705    *             .maxLength=(10)
706    *          )
707    *       )
708    *       .build();
709    *
710    *    <jc>// Parse into multiple 2d long arrays.</jc>
711    *    <jk>long</jk>[][][] myparams = formData.getAll(schema, <js>"myparam"</js>, <jk>long</jk>[][][].<jk>class</jk>);
712    * </p>
713    *
714    * <ul class='seealso'>
715    *    <li class='jf'>{@link RestContext#REST_partParser}
716    * </ul>
717    *
718    * @param schema
719    *    The schema object that defines the format of the input.
720    *    <br>If <jk>null</jk>, defaults to the schema defined on the parser.
721    *    <br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.
722    *    <br>Only used if parser is schema-aware (e.g. {@link OpenApiParser}).
723    * @param name The parameter name.
724    * @param type The class type to convert the parameter value to.
725    * @return The parameter value converted to the specified class type.
726    * @throws BadRequest Thrown if input could not be parsed.
727    * @throws InternalServerError Thrown if any other exception occurs.
728    */
729   public <T> T getAll(HttpPartSchema schema, String name, Class<T> type) throws BadRequest, InternalServerError {
730      return getAllInner(null, schema, name, getClassMeta(type));
731   }
732
733   /**
734    * Returns the specified form-data parameter values converted to POJOs using the specified {@link HttpPartParser}.
735    *
736    * <p>
737    * Meant to be used on multi-part parameters (e.g. <js>"key=1&amp;key=2&amp;key=3"</js> instead of <js>"key=@(1,2,3)"</js>)
738    *
739    * <h5 class='section'>Examples:</h5>
740    * <p class='bcode w800'>
741    *    <jc>// Pipe-delimited list of comma-delimited numbers</jc>
742    *    HttpPartSchema schema = HttpPartSchema.<jsm>create</jsm>()
743    *       .items(
744    *          HttpPartSchema.<jsm>create</jsm>()
745    *          .collectionFormat(<js>"pipes"</js>)
746    *          .items(
747    *             HttpPartSchema.<jsm>create</jsm>()
748    *             .collectionFormat(<js>"csv"</js>)
749    *             .type(<js>"integer"</js>)
750    *             .format(<js>"int64"</js>)
751    *             .minimum(<js>"0"</js>)
752    *             .maximum(<js>"100"</js>)
753    *             .minLength(1)
754    *             .maxLength=(10)
755    *          )
756    *       )
757    *       .build();
758    *
759    *    <jc>// Parse into multiple 2d long arrays.</jc>
760    *    <jk>long</jk>[][][] myparams = formData.getAll(schema, <js>"myparam"</js>, <jk>long</jk>[][][].<jk>class</jk>);
761    * </p>
762    *
763    * <ul class='seealso'>
764    *    <li class='jf'>{@link RestContext#REST_partParser}
765    * </ul>
766    *
767    * @param parser
768    *    The parser to use for parsing the string value.
769    *    <br>If <jk>null</jk>, uses the part parser defined on the resource/method.
770    * @param schema
771    *    The schema object that defines the format of the input.
772    *    <br>If <jk>null</jk>, defaults to the schema defined on the parser.
773    *    <br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.
774    *    <br>Only used if parser is schema-aware (e.g. {@link OpenApiParser}).
775    * @param name The parameter name.
776    * @param type The class type to convert the parameter value to.
777    * @return The parameter value converted to the specified class type.
778    * @throws BadRequest Thrown if input could not be parsed or fails schema validation.
779    * @throws InternalServerError Thrown if any other exception occurs.
780    */
781   public <T> T getAll(HttpPartParserSession parser, HttpPartSchema schema, String name, Class<T> type) throws BadRequest, InternalServerError {
782      return getAllInner(parser, schema, name, getClassMeta(type));
783   }
784
785   /**
786    * Same as {@link #get(String, Type, Type...)} except for use on multi-part parameters
787    * (e.g. <js>"key=1&amp;key=2&amp;key=3"</js> instead of <js>"key=@(1,2,3)"</js>)
788    *
789    * <p>
790    * This method must only be called when parsing into classes of type Collection or array.
791    *
792    * @param name The parameter name.
793    * @param type
794    *    The type of object to create.
795    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
796    * @param args
797    *    The type arguments of the class if it's a collection or map.
798    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
799    *    <br>Ignored if the main type is not a map or collection.
800    * @return The parameter value converted to the specified class type.
801    * @throws BadRequest Thrown if input could not be parsed.
802    * @throws InternalServerError Thrown if any other exception occurs.
803    */
804   public <T> T getAll(String name, Type type, Type...args) throws BadRequest, InternalServerError {
805      return getAllInner(null, null, name, this.<T>getClassMeta(type, args));
806   }
807
808   /**
809    * Same as {@link #getAll(String, Type, Type...)} but allows you to override the part parser.
810    *
811    * @param parser
812    *    The parser to use for parsing the string value.
813    *    <br>If <jk>null</jk>, uses the part parser defined on the resource/method.
814    * @param schema
815    *    The schema object that defines the format of the input.
816    *    <br>If <jk>null</jk>, defaults to the schema defined on the parser.
817    *    <br>If that's also <jk>null</jk>, defaults to {@link HttpPartSchema#DEFAULT}.
818    *    <br>Only used if parser is schema-aware (e.g. {@link OpenApiParser}).
819    * @param name The parameter name.
820    * @param type
821    *    The type of object to create.
822    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
823    * @param args
824    *    The type arguments of the class if it's a collection or map.
825    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
826    *    <br>Ignored if the main type is not a map or collection.
827    * @return The parameter value converted to the specified class type.
828    * @throws BadRequest Thrown if input could not be parsed or fails schema validation.
829    * @throws InternalServerError Thrown if any other exception occurs.
830    */
831   public <T> T getAll(HttpPartParserSession parser, HttpPartSchema schema, String name, Type type, Type...args) throws BadRequest, InternalServerError {
832      return getAllInner(parser, schema, name, this.<T>getClassMeta(type, args));
833   }
834
835   /* Workhorse method */
836   private <T> T getInner(HttpPartParserSession parser, HttpPartSchema schema, String name, T def, ClassMeta<T> cm) throws BadRequest, InternalServerError {
837      if (parser == null)
838         parser = req.getPartParser();
839      try {
840         if (cm.isMapOrBean() && isOneOf(name, "*", "")) {
841            OMap m = new OMap();
842            for (Map.Entry<String,String[]> e : this.entrySet()) {
843               String k = e.getKey();
844               HttpPartSchema pschema = schema == null ? null : schema.getProperty(k);
845               ClassMeta<?> cm2 = cm.getValueType();
846               if (cm.getValueType().isCollectionOrArray())
847                  m.put(k, getAllInner(parser, pschema, k, cm2));
848               else
849                  m.put(k, getInner(parser, pschema, k, null, cm2));
850            }
851            return req.getBeanSession().convertToType(m, cm);
852         }
853         T t = parse(parser, schema, getString(name), cm);
854         return (t == null ? def : t);
855      } catch (SchemaValidationException e) {
856         throw new BadRequest(e, "Validation failed on form-data parameter ''{0}''. ", name);
857      } catch (ParseException e) {
858         throw new BadRequest(e, "Could not parse form-data parameter ''{0}''.", name) ;
859      } catch (Exception e) {
860         throw new InternalServerError(e, "Could not parse form-data parameter ''{0}''.", name) ;
861      }
862   }
863
864   /* Workhorse method */
865   @SuppressWarnings("rawtypes")
866   <T> T getAllInner(HttpPartParserSession parser, HttpPartSchema schema, String name, ClassMeta<T> cm) throws BadRequest, InternalServerError {
867      String[] p = get(name);
868      if (schema == null)
869         schema = HttpPartSchema.DEFAULT;
870      try {
871         if (cm.isArray()) {
872            List c = new ArrayList();
873            for (int i = 0; i < p.length; i++)
874               c.add(parse(parser, schema.getItems(), p[i], cm.getElementType()));
875            return (T)toArray(c, cm.getElementType().getInnerClass());
876         } else if (cm.isCollection()) {
877            Collection c = (Collection)(cm.canCreateNewInstance() ? cm.newInstance() : new OList());
878            for (int i = 0; i < p.length; i++)
879               c.add(parse(parser, schema.getItems(), p[i], cm.getElementType()));
880            return (T)c;
881         }
882      } catch (SchemaValidationException e) {
883         throw new BadRequest(e, "Validation failed on form-data parameter ''{0}''. ", name);
884      } catch (ParseException e) {
885         throw new BadRequest(e, "Could not parse form-data parameter ''{0}''.", name) ;
886      } catch (Exception e) {
887         throw new InternalServerError(e, "Could not parse form-data parameter ''{0}''.", name) ;
888      }
889      throw new InternalServerError("Invalid call to getAll(String, ClassMeta).  Class type must be a Collection or array.");
890   }
891
892   private <T> T parse(HttpPartParserSession parser, HttpPartSchema schema, String val, ClassMeta<T> c) throws SchemaValidationException, ParseException {
893      if (parser == null)
894         parser = this.parser;
895      return parser.parse(HttpPartType.FORMDATA, schema, val, c);
896   }
897
898   /**
899    * Converts the form-data parameters to a readable string.
900    *
901    * @param sorted Sort the form-data parameters by name.
902    * @return A JSON string containing the contents of the form-data parameters.
903    */
904   public String toString(boolean sorted) {
905      Map<String,Object> m = null;
906      if (sorted)
907         m = new TreeMap<>();
908      else
909         m = new LinkedHashMap<>();
910      for (Map.Entry<String,String[]> e : this.entrySet()) {
911         String[] v = e.getValue();
912         if (v != null)
913            m.put(e.getKey(), v.length == 1 ? v[0] : v);
914      }
915      return SimpleJsonSerializer.DEFAULT.toString(m);
916   }
917
918   /**
919    * Converts this object to a query string.
920    *
921    * <p>
922    * Returned query string does not start with <js>'?'</js>.
923    *
924    * @return A new query string, or an empty string if this object is empty.
925    */
926   public String asQueryString() {
927      StringBuilder sb = new StringBuilder();
928      for (Map.Entry<String,String[]> e : this.entrySet()) {
929         for (int i = 0; i < e.getValue().length; i++) {
930            if (sb.length() > 0)
931               sb.append("&");
932            sb.append(urlEncode(e.getKey())).append('=').append(urlEncode(e.getValue()[i]));
933         }
934      }
935      return sb.toString();
936   }
937
938
939   @Override /* Object */
940   public String toString() {
941      return toString(false);
942   }
943
944   //-----------------------------------------------------------------------------------------------------------------
945   // Helper methods
946   //-----------------------------------------------------------------------------------------------------------------
947
948   private <T> ClassMeta<T> getClassMeta(Type type, Type...args) {
949      return req.getBeanSession().getClassMeta(type, args);
950   }
951
952   private <T> ClassMeta<T> getClassMeta(Class<T> type) {
953      return req.getBeanSession().getClassMeta(type);
954   }
955}