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