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