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 class='spaced-list'>
133    *    <li><b>ID:</b>  {@link org.apache.juneau.parser.Parser#PARSER_autoCloseStreams PARSER_autoCloseStreams}
134    *    <li><b>Name:</b>  <js>"Parser.autoCloseStreams.b"</js>
135    *    <li><b>Data type:</b>  <jk>boolean</jk>
136    *    <li><b>System property:</b>  <c>Parser.autoCloseStreams</c>
137    *    <li><b>Environment variable:</b>  <c>PARSER_AUTOCLOSESTREAMS</c>
138    *    <li><b>Default:</b>  <jk>false</jk>
139    *    <li><b>Session property:</b>  <jk>false</jk>
140    *    <li><b>Annotations:</b>
141    *       <ul>
142    *          <li class='ja'>{@link org.apache.juneau.parser.annotation.ParserConfig#autoCloseStreams()}
143    *       </ul>
144    *    <li><b>Methods:</b>
145    *       <ul>
146    *          <li class='jm'>{@link org.apache.juneau.parser.ParserBuilder#autoCloseStreams(boolean)}
147    *          <li class='jm'>{@link org.apache.juneau.parser.ParserBuilder#autoCloseStreams()}
148    *       </ul>
149    * </ul>
150    *
151    * <h5 class='section'>Description:</h5>
152    * <p>
153    * If <jk>true</jk>, <l>InputStreams</l> and <l>Readers</l> passed into parsers will be closed
154    * after parsing is complete.
155    *
156    * <h5 class='section'>Example:</h5>
157    * <p class='bcode w800'>
158    *    <jc>// Create a parser using strict mode.</jc>
159    *    ReaderParser p = JsonParser.
160    *       .<jsm>create</jsm>()
161    *       .autoCloseStreams()
162    *       .build();
163    *
164    *    <jc>// Same, but use property.</jc>
165    *    ReaderParser p = JsonParser.
166    *       .<jsm>create</jsm>()
167    *       .set(<jsf>PARSER_autoCloseStreams</jsf>, <jk>true</jk>)
168    *       .build();
169    *
170    *    Reader r = <jk>new</jk> FileReader(<js>"/tmp/myfile.json"</js>);
171    *    MyBean myBean = p.parse(r, MyBean.<jk>class</jk>);
172    *
173    *    <jsm>assertTrue</jsm>(r.isClosed());
174    * </p>
175    */
176   public static final String PARSER_autoCloseStreams = PREFIX + ".autoCloseStreams.b";
177
178   /**
179    * Configuration property:  Debug output lines.
180    *
181    * <h5 class='section'>Property:</h5>
182    * <ul class='spaced-list'>
183    *    <li><b>ID:</b>  {@link org.apache.juneau.parser.Parser#PARSER_debugOutputLines PARSER_debugOutputLines}
184    *    <li><b>Name:</b>  <js>"Parser.debugOutputLines.i"</js>
185    *    <li><b>Data type:</b>  <jk>int</jk>
186    *    <li><b>System property:</b>  <c>Parser.debugOutputLines</c>
187    *    <li><b>Environment variable:</b>  <c>PARSER_DEBUGOUTPUTLINES</c>
188    *    <li><b>Default:</b>  <c>5</c>
189    *    <li><b>Session property:</b>  <jk>false</jk>
190    *    <li><b>Annotations:</b>
191    *       <ul>
192    *          <li class='ja'>{@link org.apache.juneau.parser.annotation.ParserConfig#debugOutputLines()}
193    *       </ul>
194    *    <li><b>Methods:</b>
195    *       <ul>
196    *          <li class='jm'>{@link org.apache.juneau.parser.ParserBuilder#debugOutputLines(int)}
197    *       </ul>
198    * </ul>
199    *
200    * <h5 class='section'>Description:</h5>
201    * <p>
202    * When parse errors occur, this specifies the number of lines of input before and after the
203    * error location to be printed as part of the exception message.
204    *
205    * <h5 class='section'>Example:</h5>
206    * <p class='bcode w800'>
207    *    <jc>// Create a parser whose exceptions print out 100 lines before and after the parse error location.</jc>
208    *    ReaderParser p = JsonParser.
209    *       .<jsm>create</jsm>()
210    *       .debug()  <jc>// Enable debug mode to capture Reader contents as strings.</jc>
211    *       .debugOuputLines(100)
212    *       .build();
213    *
214    *    <jc>// Same, but use property.</jc>
215    *    ReaderParser p = JsonParser.
216    *       .<jsm>create</jsm>()
217    *       .set(<jsf>BEAN_debug</jsf>, <jk>true</jk>)
218    *       .set(<jsf>PARSER_debugOutputLines</jsf>, 100)
219    *       .build();
220    *
221    *    Reader r = <jk>new</jk> FileReader(<js>"/tmp/mybadfile.json"</js>);
222    *    <jk>try</jk> {
223    *       p.parse(r, Object.<jk>class</jk>);
224    *    } <jk>catch</jk> (ParseException e) {
225    *       System.<jsf>err</jsf>.println(e.getMessage());  <jc>// Will display 200 lines of the output.</jc>
226    *    }
227    * </p>
228    */
229   public static final String PARSER_debugOutputLines = PREFIX + ".debugOutputLines.i";
230
231   /**
232    * Configuration property:  Parser listener.
233    *
234    * <h5 class='section'>Property:</h5>
235    * <ul class='spaced-list'>
236    *    <li><b>ID:</b>  {@link org.apache.juneau.parser.Parser#PARSER_listener PARSER_listener}
237    *    <li><b>Name:</b>  <js>"Parser.listener.c"</js>
238    *    <li><b>Data type:</b>  <c>Class&lt;{@link org.apache.juneau.parser.ParserListener}&gt;</c>
239    *    <li><b>Default:</b>  <jk>null</jk>
240    *    <li><b>Session property:</b>  <jk>false</jk>
241    *    <li><b>Annotations:</b>
242    *       <ul>
243    *          <li class='ja'>{@link org.apache.juneau.parser.annotation.ParserConfig#listener()}
244    *       </ul>
245    *    <li><b>Methods:</b>
246    *       <ul>
247    *          <li class='jm'>{@link org.apache.juneau.parser.ParserBuilder#listener(Class)}
248    *       </ul>
249    * </ul>
250    *
251    * <h5 class='section'>Description:</h5>
252    * <p>
253    * Class used to listen for errors and warnings that occur during parsing.
254    *
255    * <h5 class='section'>Example:</h5>
256    * <p class='bcode w800'>
257    *    <jc>// Define our parser listener.</jc>
258    *    <jc>// Simply captures all unknown bean property events.</jc>
259    *    <jk>public class</jk> MyParserListener <jk>extends</jk> ParserListener {
260    *
261    *       <jc>// A simple property to store our events.</jc>
262    *       <jk>public</jk> List&lt;String&gt; <jf>events</jf> = <jk>new</jk> LinkedList&lt;&gt;();
263    *
264    *       <ja>@Override</ja>
265    *       <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) {
266    *          <jf>events</jf>.add(propertyName + <js>","</js> + line + <js>","</js> + col);
267    *       }
268    *    }
269    *
270    *    <jc>// Create a parser using our listener.</jc>
271    *    ReaderParser p = JsonParser.
272    *       .<jsm>create</jsm>()
273    *       .listener(MyParserListener.<jk>class</jk>)
274    *       .build();
275    *
276    *    <jc>// Same, but use property.</jc>
277    *    ReaderParser p = JsonParser.
278    *       .<jsm>create</jsm>()
279    *       .set(<jsf>PARSER_listener</jsf>, MyParserListener.<jk>class</jk>)
280    *       .build();
281    *
282    *    <jc>// Create a session object.</jc>
283    *    <jc>// Needed because listeners are created per-session.</jc>
284    *    <jk>try</jk> (ReaderParserSession s = p.createSession()) {
285    *
286    *       <jc>// Parse some JSON object.</jc>
287    *       MyBean myBean = s.parse(<js>"{...}"</js>, MyBean.<jk>class</jk>);
288    *
289    *       <jc>// Get the listener.</jc>
290    *       MyParserListener l = s.getListener(MyParserListener.<jk>class</jk>);
291    *
292    *       <jc>// Dump the results to the console.</jc>
293    *       SimpleJsonSerializer.<jsf>DEFAULT</jsf>.println(l.<jf>events</jf>);
294    *    }
295    * </p>
296    */
297   public static final String PARSER_listener = PREFIX + ".listener.c";
298
299   /**
300    * Configuration property:  Strict mode.
301    *
302    * <h5 class='section'>Property:</h5>
303    * <ul class='spaced-list'>
304    *    <li><b>ID:</b>  {@link org.apache.juneau.parser.Parser#PARSER_strict PARSER_strict}
305    *    <li><b>Name:</b>  <js>"Parser.strict.b"</js>
306    *    <li><b>Data type:</b>  <jk>boolean</jk>
307    *    <li><b>System property:</b>  <c>Parser.strict</c>
308    *    <li><b>Environment variable:</b>  <c>PARSER_STRICT</c>
309    *    <li><b>Default:</b>  <jk>false</jk>
310    *    <li><b>Session property:</b>  <jk>false</jk>
311    *    <li><b>Annotations:</b>
312    *       <ul>
313    *          <li class='ja'>{@link org.apache.juneau.parser.annotation.ParserConfig#strict()}
314    *       </ul>
315    *    <li><b>Methods:</b>
316    *       <ul>
317    *          <li class='jm'>{@link org.apache.juneau.parser.ParserBuilder#strict(boolean)}
318    *          <li class='jm'>{@link org.apache.juneau.parser.ParserBuilder#strict()}
319    *       </ul>
320    * </ul>
321    *
322    * <h5 class='section'>Description:</h5>
323    * <p>
324    * If <jk>true</jk>, strict mode for the parser is enabled.
325    *
326    * <p>
327    * Strict mode can mean different things for different parsers.
328    *
329    * <table class='styled'>
330    *    <tr><th>Parser class</th><th>Strict behavior</th></tr>
331    *    <tr>
332    *       <td>All reader-based parsers</td>
333    *       <td>
334    *          When enabled, throws {@link ParseException ParseExceptions} on malformed charset input.
335    *          Otherwise, malformed input is ignored.
336    *       </td>
337    *    </tr>
338    *    <tr>
339    *       <td>{@link JsonParser}</td>
340    *       <td>
341    *          When enabled, throws exceptions on the following invalid JSON syntax:
342    *          <ul>
343    *             <li>Unquoted attributes.
344    *             <li>Missing attribute values.
345    *             <li>Concatenated strings.
346    *             <li>Javascript comments.
347    *             <li>Numbers and booleans when Strings are expected.
348    *             <li>Numbers valid in Java but not JSON (e.g. octal notation, etc...)
349    *          </ul>
350    *       </td>
351    *    </tr>
352    * </table>
353    *
354    * <h5 class='section'>Example:</h5>
355    * <p class='bcode w800'>
356    *    <jc>// Create a parser using strict mode.</jc>
357    *    ReaderParser p = JsonParser.
358    *       .<jsm>create</jsm>()
359    *       .strict()
360    *       .build();
361    *
362    *    <jc>// Same, but use property.</jc>
363    *    ReaderParser p = JsonParser.
364    *       .<jsm>create</jsm>()
365    *       .set(<jsf>PARSER_strict</jsf>, <jk>true</jk>)
366    *       .build();
367    *
368    *    <jc>// Use it.</jc>
369    *    <jk>try</jk> {
370    *       String json = <js>"{unquotedAttr:'value'}"</js>;
371    *       MyBean myBean = p.parse(json, MyBean.<jk>class</jk>);
372    *    } <jk>catch</jk> (ParseException e) {
373    *       <jsm>assertTrue</jsm>(e.getMessage().contains(<js>"Unquoted attribute detected."</js>);
374    *    }
375    * </p>
376    */
377   public static final String PARSER_strict = PREFIX + ".strict.b";
378
379   /**
380    * Configuration property:  Trim parsed strings.
381    *
382    * <h5 class='section'>Property:</h5>
383    * <ul class='spaced-list'>
384    *    <li><b>ID:</b>  {@link org.apache.juneau.parser.Parser#PARSER_trimStrings PARSER_trimStrings}
385    *    <li><b>Name:</b>  <js>"Parser.trimStrings.b"</js>
386    *    <li><b>Data type:</b>  <jk>boolean</jk>
387    *    <li><b>System property:</b>  <c>Parser.trimStrings</c>
388    *    <li><b>Environment variable:</b>  <c>PARSER_TRIMSTRINGS</c>
389    *    <li><b>Default:</b>  <jk>false</jk>
390    *    <li><b>Session property:</b>  <jk>false</jk>
391    *    <li><b>Annotations:</b>
392    *       <ul>
393    *          <li class='ja'>{@link org.apache.juneau.parser.annotation.ParserConfig#trimStrings()}
394    *       </ul>
395    *    <li><b>Methods:</b>
396    *       <ul>
397    *          <li class='jm'>{@link org.apache.juneau.parser.ParserBuilder#trimStrings(boolean)}
398    *          <li class='jm'>{@link org.apache.juneau.parser.ParserBuilder#trimStrings()}
399    *       </ul>
400    * </ul>
401    *
402    * <h5 class='section'>Description:</h5>
403    * <p>
404    * If <jk>true</jk>, string values will be trimmed of whitespace using {@link String#trim()} before being added to
405    * the POJO.
406    *
407    * <h5 class='section'>Example:</h5>
408    * <p class='bcode w800'>
409    *    <jc>// Create a parser with trim-strings enabled.</jc>
410    *    ReaderParser p = JsonParser.
411    *       .<jsm>create</jsm>()
412    *       .trimStrings()
413    *       .build();
414    *
415    *    <jc>// Same, but use property.</jc>
416    *    ReaderParser p = JsonParser.
417    *       .<jsm>create</jsm>()
418    *       .set(<jsf>PARSER_trimStrings</jsf>, <jk>true</jk>)
419    *       .build();
420    *
421    *    <jc>// Use it.</jc>
422    *    String json = <js>"{foo:' bar '}"</js>;
423    *    Map&lt;String,String&gt; m = p.parse(json, HashMap.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>);
424    *    <jsm>assertEquals</jsm>(<js>"bar"</js>, m.get(<js>"foo"</js>));
425    * </p>
426    */
427   public static final String PARSER_trimStrings = PREFIX + ".trimStrings.b";
428
429   /**
430    * Configuration property:  Unbuffered.
431    *
432    * <h5 class='section'>Property:</h5>
433    * <ul class='spaced-list'>
434    *    <li><b>ID:</b>  {@link org.apache.juneau.parser.Parser#PARSER_unbuffered PARSER_unbuffered}
435    *    <li><b>Name:</b>  <js>"Parser.unbuffered.b"</js>
436    *    <li><b>Data type:</b>  <jk>boolean</jk>
437    *    <li><b>System property:</b>  <c>Parser.unbuffered</c>
438    *    <li><b>Environment variable:</b>  <c>PARSER_UNBUFFERED</c>
439    *    <li><b>Default:</b>  <jk>false</jk>
440    *    <li><b>Session property:</b>  <jk>false</jk>
441    *    <li><b>Annotations:</b>
442    *       <ul>
443    *          <li class='ja'>{@link org.apache.juneau.parser.annotation.ParserConfig#unbuffered()}
444    *       </ul>
445    *    <li><b>Methods:</b>
446    *       <ul>
447    *          <li class='jm'>{@link org.apache.juneau.parser.ParserBuilder#unbuffered(boolean)}
448    *          <li class='jm'>{@link org.apache.juneau.parser.ParserBuilder#unbuffered()}
449    *       </ul>
450    * </ul>
451    *
452    * <h5 class='section'>Description:</h5>
453    * <p>
454    * If <jk>true</jk>, don't use internal buffering during parsing.
455    *
456    * <p>
457    * This is useful in cases when you want to parse the same input stream or reader multiple times
458    * because it may contain multiple independent POJOs to parse.
459    * <br>Buffering would cause the parser to read past the current POJO in the stream.
460    *
461    * <h5 class='section'>Example:</h5>
462    * <p class='bcode w800'>
463    *    <jc>// Create a parser using strict mode.</jc>
464    *    ReaderParser p = JsonParser.
465    *       .<jsm>create</jsm>()
466    *       .unbuffered()
467    *       .build();
468    *
469    *    <jc>// Same, but use property.</jc>
470    *    ReaderParser p = JsonParser.
471    *       .<jsm>create</jsm>()
472    *       .set(<jsf>PARSER_unbuffered</jsf>, <jk>true</jk>)
473    *       .build();
474    *
475    *    <jc>// If you're calling parse on the same input multiple times, use a session instead of the parser directly.</jc>
476    *    <jc>// It's more efficient because we don't need to recalc the session settings again. </jc>
477    *    ReaderParserSession s = p.createSession();
478    *
479    *    <jc>// Read input with multiple POJOs</jc>
480    *    Reader json = <jk>new</jk> StringReader(<js>"{foo:'bar'}{foo:'baz'}"</js>);
481    *    MyBean myBean1 = s.parse(json, MyBean.<jk>class</jk>);
482    *    MyBean myBean2 = s.parse(json, MyBean.<jk>class</jk>);
483    * </p>
484    *
485    * <ul class='notes'>
486    *    <li>
487    *       This only allows for multi-input streams for the following parsers:
488    *       <ul>
489    *          <li class='jc'>{@link JsonParser}
490    *          <li class='jc'>{@link UonParser}
491    *       </ul>
492    *       It has no effect on the following parsers:
493    *       <ul>
494    *          <li class='jc'>{@link MsgPackParser} - It already doesn't use buffering.
495    *          <li class='jc'>{@link XmlParser}, {@link HtmlParser} - These use StAX which doesn't allow for more than one root element anyway.
496    *          <li>RDF parsers - These read everything into an internal model before any parsing begins.
497    *       </ul>
498    * </ul>
499    *
500    * If <jk>true</jk>, don't use internal buffering during parsing.
501    */
502   public static final String PARSER_unbuffered = PREFIX + ".unbuffered.b";
503
504   static Parser DEFAULT = new Parser(PropertyStore.create().build()) {
505      @Override
506      public ParserSession createSession(ParserSessionArgs args) {
507         throw new NoSuchMethodError();
508      }
509   };
510
511   //-------------------------------------------------------------------------------------------------------------------
512   // Instance
513   //-------------------------------------------------------------------------------------------------------------------
514
515   private final boolean trimStrings, strict, autoCloseStreams, unbuffered;
516   private final int debugOutputLines;
517   private final Class<? extends ParserListener> listener;
518
519   /** General parser properties currently set on this parser. */
520   private final MediaType[] consumes;
521
522   /**
523    * Constructor.
524    *
525    * @param ps The property store containing all the settings for this object.
526    * @param consumes The list of media types that this parser consumes (e.g. <js>"application/json"</js>).
527    */
528   protected Parser(PropertyStore ps, String...consumes) {
529      super(ps);
530
531      trimStrings = getBooleanProperty(PARSER_trimStrings, false);
532      strict = getBooleanProperty(PARSER_strict, false);
533      autoCloseStreams = getBooleanProperty(PARSER_autoCloseStreams, false);
534      debugOutputLines = getIntegerProperty(PARSER_debugOutputLines, 5);
535      unbuffered = getBooleanProperty(PARSER_unbuffered, false);
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 w800'>
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    * <c>Collection</c> classes are assumed to be followed by zero or one objects indicating the element type.
624    *
625    * <p>
626    * <c>Map</c> 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    * <ul class='notes'>
632    *    <li>
633    *       Use the {@link #parse(Object, Class)} method instead if you don't need a parameterized map/collection.
634    * </ul>
635    *
636    * @param <T> The class type of the object to create.
637    * @param input
638    *    The input.
639    *    <br>Character-based parsers can handle the following input class types:
640    *    <ul>
641    *       <li><jk>null</jk>
642    *       <li>{@link Reader}
643    *       <li>{@link CharSequence}
644    *       <li>{@link InputStream} containing UTF-8 encoded text (or charset defined by
645    *          {@link ReaderParser#RPARSER_streamCharset} property value).
646    *       <li><code><jk>byte</jk>[]</code> containing UTF-8 encoded text (or charset defined by
647    *          {@link ReaderParser#RPARSER_streamCharset} property value).
648    *       <li>{@link File} containing system encoded text (or charset defined by
649    *          {@link ReaderParser#RPARSER_fileCharset} property value).
650    *    </ul>
651    *    <br>Stream-based parsers can handle the following input class types:
652    *    <ul>
653    *       <li><jk>null</jk>
654    *       <li>{@link InputStream}
655    *       <li><code><jk>byte</jk>[]</code>
656    *       <li>{@link File}
657    *       <li>{@link CharSequence} containing encoded bytes according to the {@link InputStreamParser#ISPARSER_binaryFormat} setting.
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 Malformed input encountered.
668    * @throws IOException Thrown by underlying stream.
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, IOException {
672      return createSession().parse(input, type, args);
673   }
674
675   /**
676    * Same as {@link #parse(Object, Type, Type...)} but since it's a {@link String} input doesn't throw an {@link IOException}.
677    *
678    * @param <T> The class type of the object being created.
679    * @param input
680    *    The input.
681    *    See {@link #parse(Object, Type, Type...)} for details.
682    * @param type
683    *    The object type to create.
684    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
685    * @param args
686    *    The type arguments of the class if it's a collection or map.
687    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
688    *    <br>Ignored if the main type is not a map or collection.
689    * @return The parsed object.
690    * @throws ParseException Malformed input encountered.
691    */
692   public final <T> T parse(String input, Type type, Type...args) throws ParseException {
693      return createSession().parse(input, type, args);
694   }
695
696   /**
697    * Same as {@link #parse(Object, Type, Type...)} except optimized for a non-parameterized class.
698    *
699    * <p>
700    * This is the preferred parse method for simple types since you don't need to cast the results.
701    *
702    * <h5 class='section'>Examples:</h5>
703    * <p class='bcode w800'>
704    *    ReaderParser p = JsonParser.<jsf>DEFAULT</jsf>;
705    *
706    *    <jc>// Parse into a string.</jc>
707    *    String s = p.parse(json, String.<jk>class</jk>);
708    *
709    *    <jc>// Parse into a bean.</jc>
710    *    MyBean b = p.parse(json, MyBean.<jk>class</jk>);
711    *
712    *    <jc>// Parse into a bean array.</jc>
713    *    MyBean[] ba = p.parse(json, MyBean[].<jk>class</jk>);
714    *
715    *    <jc>// Parse into a linked-list of objects.</jc>
716    *    List l = p.parse(json, LinkedList.<jk>class</jk>);
717    *
718    *    <jc>// Parse into a map of object keys/values.</jc>
719    *    Map m = p.parse(json, TreeMap.<jk>class</jk>);
720    * </p>
721    *
722    * @param <T> The class type of the object being created.
723    * @param input
724    *    The input.
725    *    See {@link #parse(Object, Type, Type...)} for details.
726    * @param type The object type to create.
727    * @return The parsed object.
728    * @throws ParseException Malformed input encountered.
729    * @throws IOException Thrown by the underlying stream.
730    */
731   public final <T> T parse(Object input, Class<T> type) throws ParseException, IOException {
732      return createSession().parse(input, type);
733   }
734
735   /**
736    * Same as {@link #parse(Object, Class)} but since it's a {@link String} input doesn't throw an {@link IOException}.
737    *
738    * @param <T> The class type of the object being created.
739    * @param input
740    *    The input.
741    *    See {@link #parse(Object, Type, Type...)} for details.
742    * @param type The object type to create.
743    * @return The parsed object.
744    * @throws ParseException Malformed input encountered.
745    */
746   public final <T> T parse(String input, Class<T> type) throws ParseException {
747      return createSession().parse(input, type);
748   }
749
750   /**
751    * Same as {@link #parse(Object, Type, Type...)} except the type has already been converted into a {@link ClassMeta}
752    * object.
753    *
754    * <p>
755    * This is mostly an internal method used by the framework.
756    *
757    * @param <T> The class type of the object being created.
758    * @param input
759    *    The input.
760    *    See {@link #parse(Object, Type, Type...)} for details.
761    * @param type The object type to create.
762    * @return The parsed object.
763    * @throws ParseException Malformed input encountered.
764    * @throws IOException Thrown by the underlying stream.
765    */
766   public final <T> T parse(Object input, ClassMeta<T> type) throws ParseException, IOException {
767      return createSession().parse(input, type);
768   }
769
770   /**
771    * Same as {@link #parse(Object, ClassMeta)} but since it's a {@link String} input doesn't throw an {@link IOException}.
772    *
773    * @param <T> The class type of the object being created.
774    * @param input
775    *    The input.
776    *    See {@link #parse(Object, Type, Type...)} for details.
777    * @param type The object type to create.
778    * @return The parsed object.
779    * @throws ParseException Malformed input encountered.
780    */
781   public final <T> T parse(String input, ClassMeta<T> type) throws ParseException {
782      return createSession().parse(input, type);
783   }
784
785   @Override /* Context */
786   public ParserSession createSession() {
787      return createSession(createDefaultSessionArgs());
788   }
789
790   @Override /* Context */
791   public final ParserSessionArgs createDefaultSessionArgs() {
792      return new ParserSessionArgs().mediaType(getPrimaryMediaType());
793   }
794
795   //-----------------------------------------------------------------------------------------------------------------
796   // Optional methods
797   //-----------------------------------------------------------------------------------------------------------------
798
799   /**
800    * Parses the contents of the specified reader and loads the results into the specified map.
801    *
802    * <p>
803    * Reader must contain something that serializes to a map (such as text containing a JSON object).
804    *
805    * <p>
806    * Used in the following locations:
807    * <ul class='spaced-list'>
808    *    <li>
809    *       The various character-based constructors in {@link ObjectMap} (e.g.
810    *       {@link ObjectMap#ObjectMap(CharSequence,Parser)}).
811    * </ul>
812    *
813    * @param <K> The key class type.
814    * @param <V> The value class type.
815    * @param input The input.  See {@link #parse(Object, ClassMeta)} for supported input types.
816    * @param m The map being loaded.
817    * @param keyType The class type of the keys, or <jk>null</jk> to default to <code>String.<jk>class</jk></code>.
818    * @param valueType The class type of the values, or <jk>null</jk> to default to whatever is being parsed.
819    * @return The same map that was passed in to allow this method to be chained.
820    * @throws ParseException Malformed input encountered.
821    * @throws UnsupportedOperationException If not implemented.
822    */
823   public final <K,V> Map<K,V> parseIntoMap(Object input, Map<K,V> m, Type keyType, Type valueType) throws ParseException {
824      return createSession().parseIntoMap(input, m, keyType, valueType);
825   }
826
827   /**
828    * Parses the contents of the specified reader and loads the results into the specified collection.
829    *
830    * <p>
831    * Used in the following locations:
832    * <ul class='spaced-list'>
833    *    <li>
834    *       The various character-based constructors in {@link ObjectList} (e.g.
835    *       {@link ObjectList#ObjectList(CharSequence,Parser)}.
836    * </ul>
837    *
838    * @param <E> The element class type.
839    * @param input The input.  See {@link #parse(Object, ClassMeta)} for supported input types.
840    * @param c The collection being loaded.
841    * @param elementType The class type of the elements, or <jk>null</jk> to default to whatever is being parsed.
842    * @return The same collection that was passed in to allow this method to be chained.
843    * @throws ParseException Malformed input encountered.
844    * @throws UnsupportedOperationException If not implemented.
845    */
846   public final <E> Collection<E> parseIntoCollection(Object input, Collection<E> c, Type elementType) throws ParseException {
847      return createSession().parseIntoCollection(input, c, elementType);
848   }
849
850   /**
851    * Parses the specified array input with each entry in the object defined by the {@code argTypes}
852    * argument.
853    *
854    * <p>
855    * Used for converting arrays (e.g. <js>"[arg1,arg2,...]"</js>) into an {@code Object[]} that can be passed
856    * to the {@code Method.invoke(target, args)} method.
857    *
858    * <p>
859    * Used in the following locations:
860    * <ul class='spaced-list'>
861    *    <li>
862    *       Used to parse argument strings in the {@link PojoIntrospector#invokeMethod(Method, Reader)} method.
863    * </ul>
864    *
865    * @param input The input.  Subclasses can support different input types.
866    * @param argTypes Specifies the type of objects to create for each entry in the array.
867    * @return An array of parsed objects.
868    * @throws ParseException Malformed input encountered.
869    */
870   public final Object[] parseArgs(Object input, Type[] argTypes) throws ParseException {
871      if (argTypes == null || argTypes.length == 0)
872         return new Object[0];
873      return createSession().parseArgs(input, argTypes);
874   }
875
876
877   //-----------------------------------------------------------------------------------------------------------------
878   // Other methods
879   //-----------------------------------------------------------------------------------------------------------------
880
881   /**
882    * Returns the media types handled based on the values passed to the <c>consumes</c> constructor parameter.
883    *
884    * @return The list of media types.  Never <jk>null</jk>.
885    */
886   public final MediaType[] getMediaTypes() {
887      return consumes;
888   }
889
890   /**
891    * Returns the first media type handled based on the values passed to the <c>consumes</c> constructor parameter.
892    *
893    * @return The media type.
894    */
895   public final MediaType getPrimaryMediaType() {
896      return consumes == null || consumes.length == 0 ? null : consumes[0];
897   }
898
899   /**
900    * Returns <jk>true</jk> if this parser can handle the specified content type.
901    *
902    * @param contentType The content type to test.
903    * @return <jk>true</jk> if this parser can handle the specified content type.
904    */
905   public boolean canHandle(String contentType) {
906      if (contentType != null)
907         for (MediaType mt : getMediaTypes())
908            if (contentType.equals(mt.toString()))
909               return true;
910      return false;
911   }
912
913   //-----------------------------------------------------------------------------------------------------------------
914   // Properties
915   //-----------------------------------------------------------------------------------------------------------------
916
917   /**
918    * Configuration property:  Auto-close streams.
919    *
920    * @see #PARSER_autoCloseStreams
921    * @return
922    *    <jk>true</jk> if <l>InputStreams</l> and <l>Readers</l> passed into parsers will be closed
923    *    after parsing is complete.
924    */
925   protected final boolean isAutoCloseStreams() {
926      return autoCloseStreams;
927   }
928
929   /**
930    * Configuration property:  Debug output lines.
931    *
932    * @see #PARSER_debugOutputLines
933    * @return
934    *    The number of lines of input before and after the error location to be printed as part of the exception message.
935    */
936   protected final int getDebugOutputLines() {
937      return debugOutputLines;
938   }
939
940   /**
941    * Configuration property:  Parser listener.
942    *
943    * @see #PARSER_listener
944    * @return
945    *    Class used to listen for errors and warnings that occur during parsing.
946    */
947   protected final Class<? extends ParserListener> getListener() {
948      return listener;
949   }
950
951   /**
952    * Configuration property:  Strict mode.
953    *
954    * @see #PARSER_strict
955    * @return
956    *    <jk>true</jk> if strict mode for the parser is enabled.
957    */
958   protected final boolean isStrict() {
959      return strict;
960   }
961
962   /**
963    * Configuration property:  Trim parsed strings.
964    *
965    * @see #PARSER_trimStrings
966    * @return
967    *    <jk>true</jk> if string values will be trimmed of whitespace using {@link String#trim()} before being added to
968    *    the POJO.
969    */
970   protected final boolean isTrimStrings() {
971      return trimStrings;
972   }
973
974   /**
975    * Configuration property:  Unbuffered.
976    *
977    * @see #PARSER_unbuffered
978    * @return
979    *    <jk>true</jk> if parsers don't use internal buffering during parsing.
980    */
981   protected final boolean isUnbuffered() {
982      return unbuffered;
983   }
984
985   //-----------------------------------------------------------------------------------------------------------------
986   // Other methods
987   //-----------------------------------------------------------------------------------------------------------------
988
989   @Override /* Context */
990   public ObjectMap toMap() {
991      return super.toMap()
992         .append("Parser", new DefaultFilteringObjectMap()
993            .append("autoCloseStreams", autoCloseStreams)
994            .append("debugOutputLines", debugOutputLines)
995            .append("listener", listener)
996            .append("strict", strict)
997            .append("trimStrings", trimStrings)
998            .append("unbuffered", unbuffered)
999         );
1000   }
1001}