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.parser;
014
015import java.io.*;
016import java.lang.reflect.*;
017import java.util.*;
018
019import org.apache.juneau.*;
020import org.apache.juneau.annotation.*;
021import org.apache.juneau.html.*;
022import org.apache.juneau.http.*;
023import org.apache.juneau.json.*;
024import org.apache.juneau.msgpack.*;
025import org.apache.juneau.transform.*;
026import org.apache.juneau.transforms.*;
027import org.apache.juneau.uon.*;
028import org.apache.juneau.utils.*;
029import org.apache.juneau.xml.*;
030
031/**
032 * Parent class for all Juneau parsers.
033 *
034 * <h5 class='topic'>Valid data conversions</h5>
035 *
036 * Parsers can parse any parsable POJO types, as specified in the {@doc PojoCategories}.
037 *
038 * <p>
039 * Some examples of conversions are shown below...
040 * </p>
041 * <table class='styled'>
042 *    <tr>
043 *       <th>Data type</th>
044 *       <th>Class type</th>
045 *       <th>JSON example</th>
046 *       <th>XML example</th>
047 *       <th>Class examples</th>
048 *    </tr>
049 *    <tr>
050 *       <td>object</td>
051 *       <td>Maps, Java beans</td>
052 *       <td class='code'>{name:<js>'John Smith'</js>,age:21}</td>
053 *       <td class='code'><xt>&lt;object&gt;
054 *    &lt;name</xt> <xa>type</xa>=<xs>'string'</xs><xt>&gt;</xt>John Smith<xt>&lt;/name&gt;
055 *    &lt;age</xt> <xa>type</xa>=<xs>'number'</xs><xt>&gt;</xt>21<xt>&lt;/age&gt;
056 * &lt;/object&gt;</xt></td>
057 *       <td class='code'>HashMap, TreeMap&lt;String,Integer&gt;</td>
058 *    </tr>
059 *    <tr>
060 *       <td>array</td>
061 *       <td>Collections, Java arrays</td>
062 *       <td class='code'>[1,2,3]</td>
063 *       <td class='code'><xt>&lt;array&gt;
064 *    &lt;number&gt;</xt>1<xt>&lt;/number&gt;
065 *    &lt;number&gt;</xt>2<xt>&lt;/number&gt;
066 *    &lt;number&gt;</xt>3<xt>&lt;/number&gt;
067 * &lt;/array&gt;</xt></td>
068 *       <td class='code'>List&lt;Integer&gt;, <jk>int</jk>[], Float[], Set&lt;Person&gt;</td>
069 *    </tr>
070 *    <tr>
071 *       <td>number</td>
072 *       <td>Numbers</td>
073 *       <td class='code'>123</td>
074 *       <td class='code'><xt>&lt;number&gt;</xt>123<xt>&lt;/number&gt;</xt></td>
075 *       <td class='code'>Integer, Long, Float, <jk>int</jk></td>
076 *    </tr>
077 *    <tr>
078 *       <td>boolean</td>
079 *       <td>Booleans</td>
080 *       <td class='code'><jk>true</jk></td>
081 *       <td class='code'><xt>&lt;boolean&gt;</xt>true<xt>&lt;/boolean&gt;</xt></td>
082 *       <td class='code'>Boolean</td>
083 *    </tr>
084 *    <tr>
085 *       <td>string</td>
086 *       <td>CharSequences</td>
087 *       <td class='code'><js>'foobar'</js></td>
088 *       <td class='code'><xt>&lt;string&gt;</xt>foobar<xt>&lt;/string&gt;</xt></td>
089 *       <td class='code'>String, StringBuilder</td>
090 *    </tr>
091 * </table>
092 *
093 * <p>
094 * In addition, any class types with {@link PojoSwap PojoSwaps} associated with them on the registered
095 * bean context can also be passed in.
096 *
097 * <p>
098 * For example, if the {@link TemporalCalendarSwap} transform is used to generalize {@code Calendar} objects to {@code String}
099 * objects.
100 * When registered with this parser, you can construct {@code Calendar} objects from {@code Strings} using the
101 * following syntax...
102 * <p class='bcode w800'>
103 *    Calendar c = parser.parse(<js>"'Sun Mar 03 04:05:06 EST 2001'"</js>, GregorianCalendar.<jk>class</jk>);
104 * </p>
105 *
106 * <p>
107 * If <code>Object.<jk>class</jk></code> is specified as the target type, then the parser automatically determines the
108 * data types and generates the following object types...
109 * <table class='styled'>
110 *    <tr><th>JSON type</th><th>Class type</th></tr>
111 *    <tr><td>object</td><td>{@link ObjectMap}</td></tr>
112 *    <tr><td>array</td><td>{@link ObjectList}</td></tr>
113 *    <tr><td>number</td><td>{@link Number}<br>(depending on length and format, could be {@link Integer},
114 *       {@link Double}, {@link Float}, etc...)</td></tr>
115 *    <tr><td>boolean</td><td>{@link Boolean}</td></tr>
116 *    <tr><td>string</td><td>{@link String}</td></tr>
117 * </table>
118 */
119@ConfigurableContext
120public abstract class Parser extends BeanContext {
121
122   //-------------------------------------------------------------------------------------------------------------------
123   // Configurable properties
124   //-------------------------------------------------------------------------------------------------------------------
125
126   static final String PREFIX = "Parser";
127
128   /**
129    * Configuration property:  Auto-close streams.
130    *
131    * <h5 class='section'>Property:</h5>
132    * <ul>
133    *    <li><b>Name:</b>  <js>"Parser.autoCloseStreams.b"</js>
134    *    <li><b>Data type:</b>  <c>Boolean</c>
135    *    <li><b>Default:</b>  <jk>false</jk>
136    *    <li><b>Session property:</b>  <jk>false</jk>
137    *    <li><b>Methods:</b>
138    *       <ul>
139    *          <li class='jm'>{@link ParserBuilder#autoCloseStreams(boolean)}
140    *          <li class='jm'>{@link ParserBuilder#autoCloseStreams()}
141    *       </ul>
142    * </ul>
143    *
144    * <h5 class='section'>Description:</h5>
145    * <p>
146    * If <jk>true</jk>, <l>InputStreams</l> and <l>Readers</l> passed into parsers will be closed
147    * after parsing is complete.
148    *
149    * <h5 class='section'>Example:</h5>
150    * <p class='bcode w800'>
151    *    <jc>// Create a parser using strict mode.</jc>
152    *    ReaderParser p = JsonParser.
153    *       .<jsm>create</jsm>()
154    *       .autoCloseStreams()
155    *       .build();
156    *
157    *    <jc>// Same, but use property.</jc>
158    *    ReaderParser p = JsonParser.
159    *       .<jsm>create</jsm>()
160    *       .set(<jsf>PARSER_autoCloseStreams</jsf>, <jk>true</jk>)
161    *       .build();
162    *
163    *    Reader r = <jk>new</jk> FileReader(<js>"/tmp/myfile.json"</js>);
164    *    MyBean myBean = p.parse(r, MyBean.<jk>class</jk>);
165    *
166    *    <jsm>assertTrue</jsm>(r.isClosed());
167    * </p>
168    */
169   public static final String PARSER_autoCloseStreams = PREFIX + ".autoCloseStreams.b";
170
171   /**
172    * Configuration property:  Debug output lines.
173    *
174    * <h5 class='section'>Property:</h5>
175    * <ul>
176    *    <li><b>Name:</b>  <js>"Parser.debugOutputLines.i"</js>
177    *    <li><b>Data type:</b>  <c>Integer</c>
178    *    <li><b>Default:</b>  <c>5</c>
179    *    <li><b>Session property:</b>  <jk>false</jk>
180    *    <li><b>Methods:</b>
181    *       <ul>
182    *          <li class='jm'>{@link ParserBuilder#debugOutputLines(int)}
183    *       </ul>
184    * </ul>
185    *
186    * <h5 class='section'>Description:</h5>
187    * <p>
188    * When parse errors occur, this specifies the number of lines of input before and after the
189    * error location to be printed as part of the exception message.
190    *
191    * <h5 class='section'>Example:</h5>
192    * <p class='bcode w800'>
193    *    <jc>// Create a parser whose exceptions print out 100 lines before and after the parse error location.</jc>
194    *    ReaderParser p = JsonParser.
195    *       .<jsm>create</jsm>()
196    *       .debug()  <jc>// Enable debug mode to capture Reader contents as strings.</jc>
197    *       .debugOuputLines(100)
198    *       .build();
199    *
200    *    <jc>// Same, but use property.</jc>
201    *    ReaderParser p = JsonParser.
202    *       .<jsm>create</jsm>()
203    *       .set(<jsf>BEAN_debug</jsf>, <jk>true</jk>)
204    *       .set(<jsf>PARSER_debugOutputLines</jsf>, 100)
205    *       .build();
206    *
207    *    Reader r = <jk>new</jk> FileReader(<js>"/tmp/mybadfile.json"</js>);
208    *    <jk>try</jk> {
209    *       p.parse(r, Object.<jk>class</jk>);
210    *    } <jk>catch</jk> (ParseException e) {
211    *       System.<jsf>err</jsf>.println(e.getMessage());  <jc>// Will display 200 lines of the output.</jc>
212    *    }
213    * </p>
214    */
215   public static final String PARSER_debugOutputLines = PREFIX + ".debugOutputLines.i";
216
217   /**
218    * Configuration property:  Parser listener.
219    *
220    * <h5 class='section'>Property:</h5>
221    * <ul>
222    *    <li><b>Name:</b>  <js>"Parser.listener.c"</js>
223    *    <li><b>Data type:</b>  <c>Class&lt;? extends ParserListener&gt;</c>
224    *    <li><b>Default:</b>  <jk>null</jk>
225    *    <li><b>Session property:</b>  <jk>false</jk>
226    *    <li><b>Methods:</b>
227    *       <ul>
228    *          <li class='jm'>{@link ParserBuilder#listener(Class)}
229    *       </ul>
230    * </ul>
231    *
232    * <h5 class='section'>Description:</h5>
233    * <p>
234    * Class used to listen for errors and warnings that occur during parsing.
235    *
236    * <h5 class='section'>Example:</h5>
237    * <p class='bcode w800'>
238    *    <jc>// Define our parser listener.</jc>
239    *    <jc>// Simply captures all unknown bean property events.</jc>
240    *    <jk>public class</jk> MyParserListener <jk>extends</jk> ParserListener {
241    *
242    *       <jc>// A simple property to store our events.</jc>
243    *       <jk>public</jk> List&lt;String&gt; <jf>events</jf> = <jk>new</jk> LinkedList&lt;&gt;();
244    *
245    *       <ja>@Override</ja>
246    *       <jk>public</jk> &lt;T&gt; <jk>void</jk> onUnknownBeanProperty(ParserSession session, ParserPipe pipe, String propertyName, Class&lt;T&gt; beanClass, T bean, <jk>int</jk> line, <jk>int</jk> col) {
247    *          <jf>events</jf>.add(propertyName + <js>","</js> + line + <js>","</js> + col);
248    *       }
249    *    }
250    *
251    *    <jc>// Create a parser using our listener.</jc>
252    *    ReaderParser p = JsonParser.
253    *       .<jsm>create</jsm>()
254    *       .listener(MyParserListener.<jk>class</jk>)
255    *       .build();
256    *
257    *    <jc>// Same, but use property.</jc>
258    *    ReaderParser p = JsonParser.
259    *       .<jsm>create</jsm>()
260    *       .set(<jsf>PARSER_listener</jsf>, MyParserListener.<jk>class</jk>)
261    *       .build();
262    *
263    *    <jc>// Create a session object.</jc>
264    *    <jc>// Needed because listeners are created per-session.</jc>
265    *    <jk>try</jk> (ReaderParserSession s = p.createSession()) {
266    *
267    *       <jc>// Parse some JSON object.</jc>
268    *       MyBean myBean = s.parse(<js>"{...}"</js>, MyBean.<jk>class</jk>);
269    *
270    *       <jc>// Get the listener.</jc>
271    *       MyParserListener l = s.getListener(MyParserListener.<jk>class</jk>);
272    *
273    *       <jc>// Dump the results to the console.</jc>
274    *       SimpleJsonSerializer.<jsf>DEFAULT</jsf>.println(l.<jf>events</jf>);
275    *    }
276    * </p>
277    */
278   public static final String PARSER_listener = PREFIX + ".listener.c";
279
280   /**
281    * Configuration property:  Strict mode.
282    *
283    * <h5 class='section'>Property:</h5>
284    * <ul>
285    *    <li><b>Name:</b>  <js>"Parser.strict.b"</js>
286    *    <li><b>Data type:</b>  <c>Boolean</c>
287    *    <li><b>Default:</b>  <jk>false</jk>
288    *    <li><b>Session property:</b>  <jk>false</jk>
289    *    <li><b>Methods:</b>
290    *       <ul>
291    *          <li class='jm'>{@link ParserBuilder#strict(boolean)}
292    *          <li class='jm'>{@link ParserBuilder#strict()}
293    *       </ul>
294    * </ul>
295    *
296    * <h5 class='section'>Description:</h5>
297    * <p>
298    * If <jk>true</jk>, strict mode for the parser is enabled.
299    *
300    * <p>
301    * Strict mode can mean different things for different parsers.
302    *
303    * <table class='styled'>
304    *    <tr><th>Parser class</th><th>Strict behavior</th></tr>
305    *    <tr>
306    *       <td>All reader-based parsers</td>
307    *       <td>
308    *          When enabled, throws {@link ParseException ParseExceptions} on malformed charset input.
309    *          Otherwise, malformed input is ignored.
310    *       </td>
311    *    </tr>
312    *    <tr>
313    *       <td>{@link JsonParser}</td>
314    *       <td>
315    *          When enabled, throws exceptions on the following invalid JSON syntax:
316    *          <ul>
317    *             <li>Unquoted attributes.
318    *             <li>Missing attribute values.
319    *             <li>Concatenated strings.
320    *             <li>Javascript comments.
321    *             <li>Numbers and booleans when Strings are expected.
322    *             <li>Numbers valid in Java but not JSON (e.g. octal notation, etc...)
323    *          </ul>
324    *       </td>
325    *    </tr>
326    * </table>
327    *
328    * <h5 class='section'>Example:</h5>
329    * <p class='bcode w800'>
330    *    <jc>// Create a parser using strict mode.</jc>
331    *    ReaderParser p = JsonParser.
332    *       .<jsm>create</jsm>()
333    *       .strict()
334    *       .build();
335    *
336    *    <jc>// Same, but use property.</jc>
337    *    ReaderParser p = JsonParser.
338    *       .<jsm>create</jsm>()
339    *       .set(<jsf>PARSER_strict</jsf>, <jk>true</jk>)
340    *       .build();
341    *
342    *    <jc>// Use it.</jc>
343    *    <jk>try</jk> {
344    *       String json = <js>"{unquotedAttr:'value'}"</js>;
345    *       MyBean myBean = p.parse(json, MyBean.<jk>class</jk>);
346    *    } <jk>catch</jk> (ParseException e) {
347    *       <jsm>assertTrue</jsm>(e.getMessage().contains(<js>"Unquoted attribute detected."</js>);
348    *    }
349    * </p>
350    */
351   public static final String PARSER_strict = PREFIX + ".strict.b";
352
353   /**
354    * Configuration property:  Trim parsed strings.
355    *
356    * <h5 class='section'>Property:</h5>
357    * <ul>
358    *    <li><b>Name:</b>  <js>"Parser.trimStrings.b"</js>
359    *    <li><b>Data type:</b>  <c>Boolean</c>
360    *    <li><b>Default:</b>  <jk>false</jk>
361    *    <li><b>Session property:</b>  <jk>false</jk>
362    *    <li><b>Methods:</b>
363    *       <ul>
364    *          <li class='jm'>{@link ParserBuilder#trimStrings(boolean)}
365    *          <li class='jm'>{@link ParserBuilder#trimStrings()}
366    *       </ul>
367    * </ul>
368    *
369    * <h5 class='section'>Description:</h5>
370    * <p>
371    * If <jk>true</jk>, string values will be trimmed of whitespace using {@link String#trim()} before being added to
372    * the POJO.
373    *
374    * <h5 class='section'>Example:</h5>
375    * <p class='bcode w800'>
376    *    <jc>// Create a parser with trim-strings enabled.</jc>
377    *    ReaderParser p = JsonParser.
378    *       .<jsm>create</jsm>()
379    *       .trimStrings()
380    *       .build();
381    *
382    *    <jc>// Same, but use property.</jc>
383    *    ReaderParser p = JsonParser.
384    *       .<jsm>create</jsm>()
385    *       .set(<jsf>PARSER_trimStrings</jsf>, <jk>true</jk>)
386    *       .build();
387    *
388    *    <jc>// Use it.</jc>
389    *    String json = <js>"{foo:' bar '}"</js>;
390    *    Map&lt;String,String&gt; m = p.parse(json, HashMap.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>);
391    *    <jsm>assertEquals</jsm>(<js>"bar"</js>, m.get(<js>"foo"</js>));
392    * </p>
393    */
394   public static final String PARSER_trimStrings = PREFIX + ".trimStrings.b";
395
396   /**
397    * Configuration property:  Unbuffered.
398    *
399    * <h5 class='section'>Property:</h5>
400    * <ul>
401    *    <li><b>Name:</b>  <js>"Parser.unbuffered.b"</js>
402    *    <li><b>Data type:</b>  <c>Boolean</c>
403    *    <li><b>Default:</b>  <jk>false</jk>
404    *    <li><b>Session property:</b>  <jk>false</jk>
405    *    <li><b>Methods:</b>
406    *       <ul>
407    *          <li class='jm'>{@link ParserBuilder#unbuffered(boolean)}
408    *          <li class='jm'>{@link ParserBuilder#unbuffered()}
409    *       </ul>
410    * </ul>
411    *
412    * <h5 class='section'>Description:</h5>
413    * <p>
414    * If <jk>true</jk>, don't use internal buffering during parsing.
415    *
416    * <p>
417    * This is useful in cases when you want to parse the same input stream or reader multiple times
418    * because it may contain multiple independent POJOs to parse.
419    * <br>Buffering would cause the parser to read past the current POJO in the stream.
420    *
421    * <h5 class='section'>Example:</h5>
422    * <p class='bcode w800'>
423    *    <jc>// Create a parser using strict mode.</jc>
424    *    ReaderParser p = JsonParser.
425    *       .<jsm>create</jsm>()
426    *       .unbuffered()
427    *       .build();
428    *
429    *    <jc>// Same, but use property.</jc>
430    *    ReaderParser p = JsonParser.
431    *       .<jsm>create</jsm>()
432    *       .set(<jsf>PARSER_unbuffered</jsf>, <jk>true</jk>)
433    *       .build();
434    *
435    *    <jc>// If you're calling parse on the same input multiple times, use a session instead of the parser directly.</jc>
436    *    <jc>// It's more efficient because we don't need to recalc the session settings again. </jc>
437    *    ReaderParserSession s = p.createSession();
438    *
439    *    <jc>// Read input with multiple POJOs</jc>
440    *    Reader json = <jk>new</jk> StringReader(<js>"{foo:'bar'}{foo:'baz'}"</js>);
441    *    MyBean myBean1 = s.parse(json, MyBean.<jk>class</jk>);
442    *    MyBean myBean2 = s.parse(json, MyBean.<jk>class</jk>);
443    * </p>
444    *
445    * <ul class='notes'>
446    *    <li>
447    *       This only allows for multi-input streams for the following parsers:
448    *       <ul>
449    *          <li class='jc'>{@link JsonParser}
450    *          <li class='jc'>{@link UonParser}
451    *       </ul>
452    *       It has no effect on the following parsers:
453    *       <ul>
454    *          <li class='jc'>{@link MsgPackParser} - It already doesn't use buffering.
455    *          <li class='jc'>{@link XmlParser}, {@link HtmlParser} - These use StAX which doesn't allow for more than one root element anyway.
456    *          <li>RDF parsers - These read everything into an internal model before any parsing begins.
457    *       </ul>
458    * </ul>
459    *
460    * If <jk>true</jk>, don't use internal buffering during parsing.
461    */
462   public static final String PARSER_unbuffered = PREFIX + ".unbuffered.b";
463
464   static Parser DEFAULT = new Parser(PropertyStore.create().build()) {
465      @Override
466      public ParserSession createSession(ParserSessionArgs args) {
467         throw new NoSuchMethodError();
468      }
469   };
470
471   //-------------------------------------------------------------------------------------------------------------------
472   // Instance
473   //-------------------------------------------------------------------------------------------------------------------
474
475   private final boolean trimStrings, strict, autoCloseStreams, unbuffered;
476   private final int debugOutputLines;
477   private final Class<? extends ParserListener> listener;
478
479   /** General parser properties currently set on this parser. */
480   private final MediaType[] consumes;
481
482   /**
483    * Constructor.
484    *
485    * @param ps The property store containing all the settings for this object.
486    * @param consumes The list of media types that this parser consumes (e.g. <js>"application/json"</js>).
487    */
488   protected Parser(PropertyStore ps, String...consumes) {
489      super(ps);
490
491      trimStrings = getBooleanProperty(PARSER_trimStrings, false);
492      strict = getBooleanProperty(PARSER_strict, false);
493      autoCloseStreams = getBooleanProperty(PARSER_autoCloseStreams, false);
494      debugOutputLines = getIntegerProperty(PARSER_debugOutputLines, 5);
495      unbuffered = getBooleanProperty(PARSER_unbuffered, false);
496      listener = getClassProperty(PARSER_listener, ParserListener.class, null);
497      this.consumes = new MediaType[consumes.length];
498      for (int i = 0; i < consumes.length; i++) {
499         this.consumes[i] = MediaType.forString(consumes[i]);
500      }
501   }
502
503   @Override /* Context */
504   public ParserBuilder builder() {
505      return new ParserBuilder(getPropertyStore());
506   }
507
508   /**
509    * Instantiates a new clean-slate {@link ParserBuilder} object.
510    *
511    * <p>
512    * This is equivalent to simply calling <code><jk>new</jk> ParserBuilder()</code>.
513    *
514    * <p>
515    * Note that this method creates a builder initialized to all default settings, whereas {@link #builder()} copies
516    * the settings of the object called on.
517    *
518    * @return A new {@link ParserBuilder} object.
519    */
520   public static ParserBuilder create() {
521      return new ParserBuilder(PropertyStore.DEFAULT);
522   }
523
524
525   //-----------------------------------------------------------------------------------------------------------------
526   // Abstract methods
527   //-----------------------------------------------------------------------------------------------------------------
528
529   /**
530    * Returns <jk>true</jk> if this parser subclasses from {@link ReaderParser}.
531    *
532    * @return <jk>true</jk> if this parser subclasses from {@link ReaderParser}.
533    */
534   public boolean isReaderParser() {
535      return true;
536   }
537
538   /**
539    * Create the session object that will be passed in to the parse method.
540    *
541    * <p>
542    * It's up to implementers to decide what the session object looks like, although typically it's going to be a
543    * subclass of {@link ParserSession}.
544    *
545    * @param args
546    *    Runtime arguments.
547    * @return The new session.
548    */
549   public abstract ParserSession createSession(ParserSessionArgs args);
550
551
552   //-----------------------------------------------------------------------------------------------------------------
553   // Other methods
554   //-----------------------------------------------------------------------------------------------------------------
555
556   /**
557    * Parses input into the specified object type.
558    *
559    * <p>
560    * The type can be a simple type (e.g. beans, strings, numbers) or parameterized type (collections/maps).
561    *
562    * <h5 class='section'>Examples:</h5>
563    * <p class='bcode w800'>
564    *    ReaderParser p = JsonParser.<jsf>DEFAULT</jsf>;
565    *
566    *    <jc>// Parse into a linked-list of strings.</jc>
567    *    List l = p.parse(json, LinkedList.<jk>class</jk>, String.<jk>class</jk>);
568    *
569    *    <jc>// Parse into a linked-list of beans.</jc>
570    *    List l = p.parse(json, LinkedList.<jk>class</jk>, MyBean.<jk>class</jk>);
571    *
572    *    <jc>// Parse into a linked-list of linked-lists of strings.</jc>
573    *    List l = p.parse(json, LinkedList.<jk>class</jk>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);
574    *
575    *    <jc>// Parse into a map of string keys/values.</jc>
576    *    Map m = p.parse(json, TreeMap.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>);
577    *
578    *    <jc>// Parse into a map containing string keys and values of lists containing beans.</jc>
579    *    Map m = p.parse(json, TreeMap.<jk>class</jk>, String.<jk>class</jk>, List.<jk>class</jk>, MyBean.<jk>class</jk>);
580    * </p>
581    *
582    * <p>
583    * <c>Collection</c> classes are assumed to be followed by zero or one objects indicating the element type.
584    *
585    * <p>
586    * <c>Map</c> classes are assumed to be followed by zero or two meta objects indicating the key and value types.
587    *
588    * <p>
589    * The array can be arbitrarily long to indicate arbitrarily complex data structures.
590    *
591    * <ul class='notes'>
592    *    <li>
593    *       Use the {@link #parse(Object, Class)} method instead if you don't need a parameterized map/collection.
594    * </ul>
595    *
596    * @param <T> The class type of the object to create.
597    * @param input
598    *    The input.
599    *    <br>Character-based parsers can handle the following input class types:
600    *    <ul>
601    *       <li><jk>null</jk>
602    *       <li>{@link Reader}
603    *       <li>{@link CharSequence}
604    *       <li>{@link InputStream} containing UTF-8 encoded text (or charset defined by
605    *          {@link ReaderParser#RPARSER_streamCharset} property value).
606    *       <li><code><jk>byte</jk>[]</code> containing UTF-8 encoded text (or charset defined by
607    *          {@link ReaderParser#RPARSER_streamCharset} property value).
608    *       <li>{@link File} containing system encoded text (or charset defined by
609    *          {@link ReaderParser#RPARSER_fileCharset} property value).
610    *    </ul>
611    *    <br>Stream-based parsers can handle the following input class types:
612    *    <ul>
613    *       <li><jk>null</jk>
614    *       <li>{@link InputStream}
615    *       <li><code><jk>byte</jk>[]</code>
616    *       <li>{@link File}
617    *       <li>{@link CharSequence} containing encoded bytes according to the {@link InputStreamParser#ISPARSER_binaryFormat} setting.
618    *    </ul>
619    * @param type
620    *    The object type to create.
621    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
622    * @param args
623    *    The type arguments of the class if it's a collection or map.
624    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
625    *    <br>Ignored if the main type is not a map or collection.
626    * @return The parsed object.
627    * @throws ParseException Malformed input encountered.
628    * @throws IOException Thrown by underlying stream.
629    * @see BeanSession#getClassMeta(Type,Type...) for argument syntax for maps and collections.
630    */
631   public final <T> T parse(Object input, Type type, Type...args) throws ParseException, IOException {
632      return createSession().parse(input, type, args);
633   }
634
635   /**
636    * Same as {@link #parse(Object, Type, Type...)} but since it's a {@link String} input doesn't throw an {@link IOException}.
637    *
638    * @param <T> The class type of the object being created.
639    * @param input
640    *    The input.
641    *    See {@link #parse(Object, Type, Type...)} for details.
642    * @param type
643    *    The object type to create.
644    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
645    * @param args
646    *    The type arguments of the class if it's a collection or map.
647    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
648    *    <br>Ignored if the main type is not a map or collection.
649    * @return The parsed object.
650    * @throws ParseException Malformed input encountered.
651    */
652   public final <T> T parse(String input, Type type, Type...args) throws ParseException {
653      return createSession().parse(input, type, args);
654   }
655
656   /**
657    * Same as {@link #parse(Object, Type, Type...)} except optimized for a non-parameterized class.
658    *
659    * <p>
660    * This is the preferred parse method for simple types since you don't need to cast the results.
661    *
662    * <h5 class='section'>Examples:</h5>
663    * <p class='bcode w800'>
664    *    ReaderParser p = JsonParser.<jsf>DEFAULT</jsf>;
665    *
666    *    <jc>// Parse into a string.</jc>
667    *    String s = p.parse(json, String.<jk>class</jk>);
668    *
669    *    <jc>// Parse into a bean.</jc>
670    *    MyBean b = p.parse(json, MyBean.<jk>class</jk>);
671    *
672    *    <jc>// Parse into a bean array.</jc>
673    *    MyBean[] ba = p.parse(json, MyBean[].<jk>class</jk>);
674    *
675    *    <jc>// Parse into a linked-list of objects.</jc>
676    *    List l = p.parse(json, LinkedList.<jk>class</jk>);
677    *
678    *    <jc>// Parse into a map of object keys/values.</jc>
679    *    Map m = p.parse(json, TreeMap.<jk>class</jk>);
680    * </p>
681    *
682    * @param <T> The class type of the object being created.
683    * @param input
684    *    The input.
685    *    See {@link #parse(Object, Type, Type...)} for details.
686    * @param type The object type to create.
687    * @return The parsed object.
688    * @throws ParseException Malformed input encountered.
689    * @throws IOException Thrown by the underlying stream.
690    */
691   public final <T> T parse(Object input, Class<T> type) throws ParseException, IOException {
692      return createSession().parse(input, type);
693   }
694
695   /**
696    * Same as {@link #parse(Object, Class)} but since it's a {@link String} input doesn't throw an {@link IOException}.
697    *
698    * @param <T> The class type of the object being created.
699    * @param input
700    *    The input.
701    *    See {@link #parse(Object, Type, Type...)} for details.
702    * @param type The object type to create.
703    * @return The parsed object.
704    * @throws ParseException Malformed input encountered.
705    */
706   public final <T> T parse(String input, Class<T> type) throws ParseException {
707      return createSession().parse(input, type);
708   }
709
710   /**
711    * Same as {@link #parse(Object, Type, Type...)} except the type has already been converted into a {@link ClassMeta}
712    * object.
713    *
714    * <p>
715    * This is mostly an internal method used by the framework.
716    *
717    * @param <T> The class type of the object being created.
718    * @param input
719    *    The input.
720    *    See {@link #parse(Object, Type, Type...)} for details.
721    * @param type The object type to create.
722    * @return The parsed object.
723    * @throws ParseException Malformed input encountered.
724    * @throws IOException Thrown by the underlying stream.
725    */
726   public final <T> T parse(Object input, ClassMeta<T> type) throws ParseException, IOException {
727      return createSession().parse(input, type);
728   }
729
730   /**
731    * Same as {@link #parse(Object, ClassMeta)} but since it's a {@link String} input doesn't throw an {@link IOException}.
732    *
733    * @param <T> The class type of the object being created.
734    * @param input
735    *    The input.
736    *    See {@link #parse(Object, Type, Type...)} for details.
737    * @param type The object type to create.
738    * @return The parsed object.
739    * @throws ParseException Malformed input encountered.
740    */
741   public final <T> T parse(String input, ClassMeta<T> type) throws ParseException {
742      return createSession().parse(input, type);
743   }
744
745   @Override /* Context */
746   public ParserSession createSession() {
747      return createSession(createDefaultSessionArgs());
748   }
749
750   @Override /* Context */
751   public final ParserSessionArgs createDefaultSessionArgs() {
752      return new ParserSessionArgs().mediaType(getPrimaryMediaType());
753   }
754
755   //-----------------------------------------------------------------------------------------------------------------
756   // Optional methods
757   //-----------------------------------------------------------------------------------------------------------------
758
759   /**
760    * Parses the contents of the specified reader and loads the results into the specified map.
761    *
762    * <p>
763    * Reader must contain something that serializes to a map (such as text containing a JSON object).
764    *
765    * <p>
766    * Used in the following locations:
767    * <ul class='spaced-list'>
768    *    <li>
769    *       The various character-based constructors in {@link ObjectMap} (e.g.
770    *       {@link ObjectMap#ObjectMap(CharSequence,Parser)}).
771    * </ul>
772    *
773    * @param <K> The key class type.
774    * @param <V> The value class type.
775    * @param input The input.  See {@link #parse(Object, ClassMeta)} for supported input types.
776    * @param m The map being loaded.
777    * @param keyType The class type of the keys, or <jk>null</jk> to default to <code>String.<jk>class</jk></code>.
778    * @param valueType The class type of the values, or <jk>null</jk> to default to whatever is being parsed.
779    * @return The same map that was passed in to allow this method to be chained.
780    * @throws ParseException Malformed input encountered.
781    * @throws UnsupportedOperationException If not implemented.
782    */
783   public final <K,V> Map<K,V> parseIntoMap(Object input, Map<K,V> m, Type keyType, Type valueType) throws ParseException {
784      return createSession().parseIntoMap(input, m, keyType, valueType);
785   }
786
787   /**
788    * Parses the contents of the specified reader and loads the results into the specified collection.
789    *
790    * <p>
791    * Used in the following locations:
792    * <ul class='spaced-list'>
793    *    <li>
794    *       The various character-based constructors in {@link ObjectList} (e.g.
795    *       {@link ObjectList#ObjectList(CharSequence,Parser)}.
796    * </ul>
797    *
798    * @param <E> The element class type.
799    * @param input The input.  See {@link #parse(Object, ClassMeta)} for supported input types.
800    * @param c The collection being loaded.
801    * @param elementType The class type of the elements, or <jk>null</jk> to default to whatever is being parsed.
802    * @return The same collection that was passed in to allow this method to be chained.
803    * @throws ParseException Malformed input encountered.
804    * @throws UnsupportedOperationException If not implemented.
805    */
806   public final <E> Collection<E> parseIntoCollection(Object input, Collection<E> c, Type elementType) throws ParseException {
807      return createSession().parseIntoCollection(input, c, elementType);
808   }
809
810   /**
811    * Parses the specified array input with each entry in the object defined by the {@code argTypes}
812    * argument.
813    *
814    * <p>
815    * Used for converting arrays (e.g. <js>"[arg1,arg2,...]"</js>) into an {@code Object[]} that can be passed
816    * to the {@code Method.invoke(target, args)} method.
817    *
818    * <p>
819    * Used in the following locations:
820    * <ul class='spaced-list'>
821    *    <li>
822    *       Used to parse argument strings in the {@link PojoIntrospector#invokeMethod(Method, Reader)} method.
823    * </ul>
824    *
825    * @param input The input.  Subclasses can support different input types.
826    * @param argTypes Specifies the type of objects to create for each entry in the array.
827    * @return An array of parsed objects.
828    * @throws ParseException Malformed input encountered.
829    */
830   public final Object[] parseArgs(Object input, Type[] argTypes) throws ParseException {
831      if (argTypes == null || argTypes.length == 0)
832         return new Object[0];
833      return createSession().parseArgs(input, argTypes);
834   }
835
836
837   //-----------------------------------------------------------------------------------------------------------------
838   // Other methods
839   //-----------------------------------------------------------------------------------------------------------------
840
841   /**
842    * Returns the media types handled based on the values passed to the <c>consumes</c> constructor parameter.
843    *
844    * @return The list of media types.  Never <jk>null</jk>.
845    */
846   public final MediaType[] getMediaTypes() {
847      return consumes;
848   }
849
850   /**
851    * Returns the first media type handled based on the values passed to the <c>consumes</c> constructor parameter.
852    *
853    * @return The media type.
854    */
855   public final MediaType getPrimaryMediaType() {
856      return consumes == null || consumes.length == 0 ? null : consumes[0];
857   }
858
859   /**
860    * Returns <jk>true</jk> if this parser can handle the specified content type.
861    *
862    * @param contentType The content type to test.
863    * @return <jk>true</jk> if this parser can handle the specified content type.
864    */
865   public boolean canHandle(String contentType) {
866      if (contentType != null)
867         for (MediaType mt : getMediaTypes())
868            if (contentType.equals(mt.toString()))
869               return true;
870      return false;
871   }
872
873   //-----------------------------------------------------------------------------------------------------------------
874   // Properties
875   //-----------------------------------------------------------------------------------------------------------------
876
877   /**
878    * Configuration property:  Auto-close streams.
879    *
880    * @see #PARSER_autoCloseStreams
881    * @return
882    *    <jk>true</jk> if <l>InputStreams</l> and <l>Readers</l> passed into parsers will be closed
883    *    after parsing is complete.
884    */
885   protected final boolean isAutoCloseStreams() {
886      return autoCloseStreams;
887   }
888
889   /**
890    * Configuration property:  Debug output lines.
891    *
892    * @see #PARSER_debugOutputLines
893    * @return
894    *    The number of lines of input before and after the error location to be printed as part of the exception message.
895    */
896   protected final int getDebugOutputLines() {
897      return debugOutputLines;
898   }
899
900   /**
901    * Configuration property:  Parser listener.
902    *
903    * @see #PARSER_listener
904    * @return
905    *    Class used to listen for errors and warnings that occur during parsing.
906    */
907   protected final Class<? extends ParserListener> getListener() {
908      return listener;
909   }
910
911   /**
912    * Configuration property:  Strict mode.
913    *
914    * @see #PARSER_strict
915    * @return
916    *    <jk>true</jk> if strict mode for the parser is enabled.
917    */
918   protected final boolean isStrict() {
919      return strict;
920   }
921
922   /**
923    * Configuration property:  Trim parsed strings.
924    *
925    * @see #PARSER_trimStrings
926    * @return
927    *    <jk>true</jk> if string values will be trimmed of whitespace using {@link String#trim()} before being added to
928    *    the POJO.
929    */
930   protected final boolean isTrimStrings() {
931      return trimStrings;
932   }
933
934   /**
935    * Configuration property:  Unbuffered.
936    *
937    * @see #PARSER_unbuffered
938    * @return
939    *    <jk>true</jk> if parsers don't use internal buffering during parsing.
940    */
941   protected final boolean isUnbuffered() {
942      return unbuffered;
943   }
944
945   //-----------------------------------------------------------------------------------------------------------------
946   // Other methods
947   //-----------------------------------------------------------------------------------------------------------------
948
949   @Override /* Context */
950   public ObjectMap toMap() {
951      return super.toMap()
952         .append("Parser", new DefaultFilteringObjectMap()
953            .append("autoCloseStreams", autoCloseStreams)
954            .append("debugOutputLines", debugOutputLines)
955            .append("listener", listener)
956            .append("strict", strict)
957            .append("trimStrings", trimStrings)
958            .append("unbuffered", unbuffered)
959         );
960   }
961}