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 static org.apache.juneau.internal.StringUtils.*;
016import static org.apache.juneau.parser.Parser.*;
017
018import java.io.*;
019import java.lang.reflect.*;
020import java.util.*;
021
022import org.apache.juneau.*;
023import org.apache.juneau.annotation.*;
024import org.apache.juneau.collections.*;
025import org.apache.juneau.transform.*;
026import org.apache.juneau.utils.*;
027
028/**
029 * Session object that lives for the duration of a single use of {@link Parser}.
030 *
031 * <p>
032 * This class is NOT thread safe.
033 * It is typically discarded after one-time use although it can be reused against multiple inputs.
034 */
035public abstract class ParserSession extends BeanSession {
036
037   private final Parser ctx;
038   private final Method javaMethod;
039   private final Object outer;
040
041   // Writable properties.
042   private BeanPropertyMeta currentProperty;
043   private ClassMeta<?> currentClass;
044   private final ParserListener listener;
045
046   private Position mark = new Position(-1);
047
048   private ParserPipe pipe;
049
050   /**
051    * Create a new session using properties specified in the context.
052    *
053    * @param ctx
054    *    The context creating this session object.
055    *    The context contains all the configuration settings for this object.
056    * @param args
057    *    Runtime session arguments.
058    */
059   protected ParserSession(Parser ctx, ParserSessionArgs args) {
060      super(ctx, args == null ? ParserSessionArgs.DEFAULT : args);
061      args = args == null ? ParserSessionArgs.DEFAULT : args;
062      this.ctx = ctx;
063      javaMethod = args.javaMethod;
064      outer = args.outer;
065      listener = getInstanceProperty(PARSER_listener, ParserListener.class, ctx.getListener());
066   }
067
068   /**
069    * Default constructor.
070    *
071    * @param args
072    *    Runtime session arguments.
073    */
074   protected ParserSession(ParserSessionArgs args) {
075      this(Parser.DEFAULT, args);
076   }
077
078   //-----------------------------------------------------------------------------------------------------------------
079   // Abstract methods
080   //-----------------------------------------------------------------------------------------------------------------
081
082   /**
083    * Workhorse method.
084    *
085    * <p>
086    * Subclasses are expected to implement this method.
087    *
088    * @param pipe Where to get the input from.
089    * @param type
090    *    The class type of the object to create.
091    *    If <jk>null</jk> or <code>Object.<jk>class</jk></code>, object type is based on what's being parsed.
092    *    For example, when parsing JSON text, it may return a <c>String</c>, <c>Number</c>,
093    *    <c>OMap</c>, etc...
094    * @param <T> The class type of the object to create.
095    * @return The parsed object.
096    * @throws IOException Thrown by underlying stream.
097    * @throws ParseException Malformed input encountered.
098    * @throws ExecutableException Exception occurred on invoked constructor/method/field.
099    */
100   protected abstract <T> T doParse(ParserPipe pipe, ClassMeta<T> type) throws IOException, ParseException, ExecutableException;
101
102   /**
103    * Returns <jk>true</jk> if this parser subclasses from {@link ReaderParser}.
104    *
105    * @return <jk>true</jk> if this parser subclasses from {@link ReaderParser}.
106    */
107   public abstract boolean isReaderParser();
108
109
110   //-----------------------------------------------------------------------------------------------------------------
111   // Other methods
112   //-----------------------------------------------------------------------------------------------------------------
113
114   /**
115    * Wraps the specified input object into a {@link ParserPipe} object so that it can be easily converted into
116    * a stream or reader.
117    *
118    * @param input
119    *    The input.
120    *    <br>For character-based parsers, this can be any of the following types:
121    *    <ul>
122    *       <li><jk>null</jk>
123    *       <li>{@link Reader}
124    *       <li>{@link CharSequence}
125    *       <li>{@link InputStream} containing UTF-8 encoded text (or whatever the encoding specified by
126    *          {@link ReaderParser#RPARSER_streamCharset}).
127    *       <li><code><jk>byte</jk>[]</code> containing UTF-8 encoded text (or whatever the encoding specified by
128    *          {@link ReaderParser#RPARSER_streamCharset}).
129    *       <li>{@link File} containing system encoded text (or whatever the encoding specified by
130    *          {@link ReaderParser#RPARSER_fileCharset}).
131    *    </ul>
132    *    <br>For byte-based parsers, this can be any of the following types:
133    *    <ul>
134    *       <li><jk>null</jk>
135    *       <li>{@link InputStream}
136    *       <li><code><jk>byte</jk>[]</code>
137    *       <li>{@link File}
138    *       <li>{@link CharSequence} containing encoded bytes according to the {@link InputStreamParser#ISPARSER_binaryFormat} setting.
139    *    </ul>
140    * @return
141    *    A new {@link ParserPipe} wrapper around the specified input object.
142    */
143   protected ParserPipe createPipe(Object input) {
144      return null;
145   }
146
147   /**
148    * Returns information used to determine at what location in the parse a failure occurred.
149    *
150    * @return A map, typically containing something like <c>{line:123,column:456,currentProperty:"foobar"}</c>
151    */
152   public final OMap getLastLocation() {
153      OMap m = new OMap();
154      if (currentClass != null)
155         m.put("currentClass", currentClass.toString(true));
156      if (currentProperty != null)
157         m.put("currentProperty", currentProperty);
158      return m;
159   }
160
161   /**
162    * Returns the Java method that invoked this parser.
163    *
164    * <p>
165    * When using the REST API, this is the Java method invoked by the REST call.
166    * Can be used to access annotations defined on the method or class.
167    *
168    * @return The Java method that invoked this parser.
169   */
170   protected final Method getJavaMethod() {
171      return javaMethod;
172   }
173
174   /**
175    * Returns the outer object used for instantiating top-level non-static member classes.
176    *
177    * <p>
178    * When using the REST API, this is the servlet object.
179    *
180    * @return The outer object.
181   */
182   protected final Object getOuter() {
183      return outer;
184   }
185
186   /**
187    * Sets the current bean property being parsed for proper error messages.
188    *
189    * @param currentProperty The current property being parsed.
190    */
191   protected final void setCurrentProperty(BeanPropertyMeta currentProperty) {
192      this.currentProperty = currentProperty;
193   }
194
195   /**
196    * Sets the current class being parsed for proper error messages.
197    *
198    * @param currentClass The current class being parsed.
199    */
200   protected final void setCurrentClass(ClassMeta<?> currentClass) {
201      this.currentClass = currentClass;
202   }
203
204   /**
205    * Trims the specified object if it's a <c>String</c> and {@link #isTrimStrings()} returns <jk>true</jk>.
206    *
207    * @param o The object to trim.
208    * @return The trimmed string if it's a string.
209    */
210   @SuppressWarnings("unchecked")
211   protected final <K> K trim(K o) {
212      if (isTrimStrings() && o instanceof String)
213         return (K)o.toString().trim();
214      return o;
215
216   }
217
218   /**
219    * Trims the specified string if {@link ParserSession#isTrimStrings()} returns <jk>true</jk>.
220    *
221    * @param s The input string to trim.
222    * @return The trimmed string, or <jk>null</jk> if the input was <jk>null</jk>.
223    */
224   protected final String trim(String s) {
225      if (isTrimStrings() && s != null)
226         return s.trim();
227      return s;
228   }
229
230   /**
231    * Converts the specified <c>OMap</c> into a bean identified by the <js>"_type"</js> property in the map.
232    *
233    * @param m The map to convert to a bean.
234    * @param pMeta The current bean property being parsed.
235    * @param eType The current expected type being parsed.
236    * @return
237    *    The converted bean, or the same map if the <js>"_type"</js> entry wasn't found or didn't resolve to a bean.
238    */
239   protected final Object cast(OMap m, BeanPropertyMeta pMeta, ClassMeta<?> eType) {
240
241      String btpn = getBeanTypePropertyName(eType);
242
243      Object o = m.get(btpn);
244      if (o == null)
245         return m;
246      String typeName = o.toString();
247
248      ClassMeta<?> cm = getClassMeta(typeName, pMeta, eType);
249
250      if (cm != null) {
251         BeanMap<?> bm = m.getBeanSession().newBeanMap(cm.getInnerClass());
252
253         // Iterate through all the entries in the map and set the individual field values.
254         for (Map.Entry<String,Object> e : m.entrySet()) {
255            String k = e.getKey();
256            Object v = e.getValue();
257            if (! k.equals(btpn)) {
258               // Attempt to recursively cast child maps.
259               if (v instanceof OMap)
260                  v = cast((OMap)v, pMeta, eType);
261               bm.put(k, v);
262            }
263         }
264         return bm.getBean();
265      }
266
267      return m;
268   }
269
270   /**
271    * Give the specified dictionary name, resolve it to a class.
272    *
273    * @param typeName The dictionary name to resolve.
274    * @param pMeta The bean property we're currently parsing.
275    * @param eType The expected type we're currently parsing.
276    * @return The resolved class, or <jk>null</jk> if the type name could not be resolved.
277    */
278   protected final ClassMeta<?> getClassMeta(String typeName, BeanPropertyMeta pMeta, ClassMeta<?> eType) {
279      BeanRegistry br = null;
280
281      // Resolve via @Beanp(dictionary={})
282      if (pMeta != null) {
283         br = pMeta.getBeanRegistry();
284         if (br != null && br.hasName(typeName))
285            return br.getClassMeta(typeName);
286      }
287
288      // Resolve via @Bean(dictionary={}) on the expected type where the
289      // expected type is an interface with subclasses.
290      if (eType != null) {
291         br = eType.getBeanRegistry();
292         if (br != null && br.hasName(typeName))
293            return br.getClassMeta(typeName);
294      }
295
296      // Last resort, resolve using the session registry.
297      return getBeanRegistry().getClassMeta(typeName);
298   }
299
300   /**
301    * Specialized warning when an exception is thrown while executing a bean setter.
302    *
303    * @param p The bean map entry representing the bean property.
304    * @param t The throwable that the bean setter threw.
305    */
306   protected final void onBeanSetterException(BeanPropertyMeta p, Throwable t) {
307      if (listener != null)
308         listener.onBeanSetterException(this, t, p);
309      String prefix = "";
310      addWarning("{0}Could not call setValue() on property ''{1}'' of class ''{2}'', exception = {3}", prefix,
311         p.getName(), p.getBeanMeta().getClassMeta(), t.getLocalizedMessage());
312   }
313
314   /**
315    * Method that gets called when an unknown bean property name is encountered.
316    *
317    * @param propertyName The unknown bean property name.
318    * @param beanMap The bean that doesn't have the expected property.
319    * @param value The parsed value.
320    * @throws ParseException
321    *    Automatically thrown if {@link BeanContext#BEAN_ignoreUnknownBeanProperties} setting on this parser is
322    *    <jk>false</jk>
323    * @param <T> The class type of the bean map that doesn't have the expected property.
324    */
325   protected final <T> void onUnknownProperty(String propertyName, BeanMap<T> beanMap, Object value) throws ParseException {
326      if (propertyName.equals(getBeanTypePropertyName(beanMap.getClassMeta())))
327         return;
328      if (! isIgnoreUnknownBeanProperties())
329         if (value != null || ! isIgnoreUnknownNullBeanProperties())
330            throw new ParseException(this,
331               "Unknown property ''{0}'' encountered while trying to parse into class ''{1}''", propertyName,
332               beanMap.getClassMeta());
333      if (listener != null)
334         listener.onUnknownBeanProperty(this, propertyName, beanMap.getClassMeta().getInnerClass(), beanMap.getBean());
335   }
336
337   /**
338    * Parses input into the specified object type.
339    *
340    * <p>
341    * The type can be a simple type (e.g. beans, strings, numbers) or parameterized type (collections/maps).
342    *
343    * <h5 class='section'>Examples:</h5>
344    * <p class='bcode w800'>
345    *    ReaderParser p = JsonParser.<jsf>DEFAULT</jsf>;
346    *
347    *    <jc>// Parse into a linked-list of strings.</jc>
348    *    List l = p.parse(json, LinkedList.<jk>class</jk>, String.<jk>class</jk>);
349    *
350    *    <jc>// Parse into a linked-list of beans.</jc>
351    *    List l = p.parse(json, LinkedList.<jk>class</jk>, MyBean.<jk>class</jk>);
352    *
353    *    <jc>// Parse into a linked-list of linked-lists of strings.</jc>
354    *    List l = p.parse(json, LinkedList.<jk>class</jk>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);
355    *
356    *    <jc>// Parse into a map of string keys/values.</jc>
357    *    Map m = p.parse(json, TreeMap.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>);
358    *
359    *    <jc>// Parse into a map containing string keys and values of lists containing beans.</jc>
360    *    Map m = p.parse(json, TreeMap.<jk>class</jk>, String.<jk>class</jk>, List.<jk>class</jk>, MyBean.<jk>class</jk>);
361    * </p>
362    *
363    * <p>
364    * <c>Collection</c> classes are assumed to be followed by zero or one objects indicating the element type.
365    *
366    * <p>
367    * <c>Map</c> classes are assumed to be followed by zero or two meta objects indicating the key and value types.
368    *
369    * <p>
370    * The array can be arbitrarily long to indicate arbitrarily complex data structures.
371    *
372    * <ul class='notes'>
373    *    <li>
374    *       Use the {@link #parse(Object, Class)} method instead if you don't need a parameterized map/collection.
375    * </ul>
376    *
377    * @param <T> The class type of the object to create.
378    * @param input
379    *    The input.
380    *    <br>Character-based parsers can handle the following input class types:
381    *    <ul>
382    *       <li><jk>null</jk>
383    *       <li>{@link Reader}
384    *       <li>{@link CharSequence}
385    *       <li>{@link InputStream} containing UTF-8 encoded text (or charset defined by
386    *          {@link ReaderParser#RPARSER_streamCharset} property value).
387    *       <li><code><jk>byte</jk>[]</code> containing UTF-8 encoded text (or charset defined by
388    *          {@link ReaderParser#RPARSER_streamCharset} property value).
389    *       <li>{@link File} containing system encoded text (or charset defined by
390    *          {@link ReaderParser#RPARSER_fileCharset} property value).
391    *    </ul>
392    *    <br>Stream-based parsers can handle the following input class types:
393    *    <ul>
394    *       <li><jk>null</jk>
395    *       <li>{@link InputStream}
396    *       <li><code><jk>byte</jk>[]</code>
397    *       <li>{@link File}
398    *    </ul>
399    * @param type
400    *    The object type to create.
401    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
402    * @param args
403    *    The type arguments of the class if it's a collection or map.
404    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
405    *    <br>Ignored if the main type is not a map or collection.
406    * @return The parsed object.
407    * @throws ParseException Malformed input encountered.
408    * @see BeanSession#getClassMeta(Type,Type...) for argument syntax for maps and collections.
409    * @throws IOException Thrown by the underlying stream.
410    */
411   @SuppressWarnings("unchecked")
412   public final <T> T parse(Object input, Type type, Type...args) throws ParseException, IOException {
413      try (ParserPipe pipe = createPipe(input)) {
414         return (T)parseInner(pipe, getClassMeta(type, args));
415      }
416   }
417
418   /**
419    * Same as {@link #parse(Object,Type,Type...)} but parses from a string and doesn't throw an {@link IOException}.
420    *
421    * @param <T> The class type of the object to create.
422    * @param input
423    *    The input.
424    *    <br>Character-based parsers can handle the following input class types:
425    *    <ul>
426    *       <li><jk>null</jk>
427    *       <li>{@link Reader}
428    *       <li>{@link CharSequence}
429    *       <li>{@link InputStream} containing UTF-8 encoded text (or charset defined by
430    *          {@link ReaderParser#RPARSER_streamCharset} property value).
431    *       <li><code><jk>byte</jk>[]</code> containing UTF-8 encoded text (or charset defined by
432    *          {@link ReaderParser#RPARSER_streamCharset} property value).
433    *       <li>{@link File} containing system encoded text (or charset defined by
434    *          {@link ReaderParser#RPARSER_fileCharset} property value).
435    *    </ul>
436    *    <br>Stream-based parsers can handle the following input class types:
437    *    <ul>
438    *       <li><jk>null</jk>
439    *       <li>{@link InputStream}
440    *       <li><code><jk>byte</jk>[]</code>
441    *       <li>{@link File}
442    *    </ul>
443    * @param type
444    *    The object type to create.
445    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
446    * @param args
447    *    The type arguments of the class if it's a collection or map.
448    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
449    *    <br>Ignored if the main type is not a map or collection.
450    * @return The parsed object.
451    * @throws ParseException Malformed input encountered.
452    * @see BeanSession#getClassMeta(Type,Type...) for argument syntax for maps and collections.
453    */
454   @SuppressWarnings("unchecked")
455   public final <T> T parse(String input, Type type, Type...args) throws ParseException {
456      try (ParserPipe pipe = createPipe(input)) {
457         return (T)parseInner(pipe, getClassMeta(type, args));
458      } catch (IOException e) {
459         throw new ParseException(e); // Shouldn't happen.
460      }
461   }
462
463   /**
464    * Same as {@link #parse(Object, Type, Type...)} except optimized for a non-parameterized class.
465    *
466    * <p>
467    * This is the preferred parse method for simple types since you don't need to cast the results.
468    *
469    * <h5 class='section'>Examples:</h5>
470    * <p class='bcode w800'>
471    *    ReaderParser p = JsonParser.<jsf>DEFAULT</jsf>;
472    *
473    *    <jc>// Parse into a string.</jc>
474    *    String s = p.parse(json, String.<jk>class</jk>);
475    *
476    *    <jc>// Parse into a bean.</jc>
477    *    MyBean b = p.parse(json, MyBean.<jk>class</jk>);
478    *
479    *    <jc>// Parse into a bean array.</jc>
480    *    MyBean[] ba = p.parse(json, MyBean[].<jk>class</jk>);
481    *
482    *    <jc>// Parse into a linked-list of objects.</jc>
483    *    List l = p.parse(json, LinkedList.<jk>class</jk>);
484    *
485    *    <jc>// Parse into a map of object keys/values.</jc>
486    *    Map m = p.parse(json, TreeMap.<jk>class</jk>);
487    * </p>
488    *
489    * @param <T> The class type of the object being created.
490    * @param input
491    *    The input.
492    *    See {@link #parse(Object, Type, Type...)} for details.
493    * @param type The object type to create.
494    * @return The parsed object.
495    * @throws ParseException Malformed input encountered.
496    * @throws IOException Thrown by the underlying stream.
497    */
498   public final <T> T parse(Object input, Class<T> type) throws ParseException, IOException {
499      try (ParserPipe pipe = createPipe(input)) {
500         return parseInner(pipe, getClassMeta(type));
501      }
502   }
503
504   /**
505    * Same as {@link #parse(Object, Class)} but parses from a string and doesn't throw an {@link IOException}.
506    *
507    * <p>
508    * This is the preferred parse method for simple types since you don't need to cast the results.
509    *
510    * <h5 class='section'>Examples:</h5>
511    * <p class='bcode w800'>
512    *    ReaderParser p = JsonParser.<jsf>DEFAULT</jsf>;
513    *
514    *    <jc>// Parse into a string.</jc>
515    *    String s = p.parse(json, String.<jk>class</jk>);
516    *
517    *    <jc>// Parse into a bean.</jc>
518    *    MyBean b = p.parse(json, MyBean.<jk>class</jk>);
519    *
520    *    <jc>// Parse into a bean array.</jc>
521    *    MyBean[] ba = p.parse(json, MyBean[].<jk>class</jk>);
522    *
523    *    <jc>// Parse into a linked-list of objects.</jc>
524    *    List l = p.parse(json, LinkedList.<jk>class</jk>);
525    *
526    *    <jc>// Parse into a map of object keys/values.</jc>
527    *    Map m = p.parse(json, TreeMap.<jk>class</jk>);
528    * </p>
529    *
530    * @param <T> The class type of the object being created.
531    * @param input
532    *    The input.
533    *    See {@link #parse(Object, Type, Type...)} for details.
534    * @param type The object type to create.
535    * @return The parsed object.
536    * @throws ParseException Malformed input encountered.
537    */
538   public final <T> T parse(String input, Class<T> type) throws ParseException {
539      try (ParserPipe pipe = createPipe(input)) {
540         return parseInner(pipe, getClassMeta(type));
541      } catch (IOException e) {
542         throw new ParseException(e); // Shouldn't happen.
543      }
544   }
545
546   /**
547    * Same as {@link #parse(Object, Type, Type...)} except the type has already been converted into a {@link ClassMeta}
548    * object.
549    *
550    * <p>
551    * This is mostly an internal method used by the framework.
552    *
553    * @param <T> The class type of the object being created.
554    * @param input
555    *    The input.
556    *    See {@link #parse(Object, Type, Type...)} for details.
557    * @param type The object type to create.
558    * @return The parsed object.
559    * @throws ParseException Malformed input encountered.
560    * @throws IOException Thrown by the underlying stream.
561    */
562   public final <T> T parse(Object input, ClassMeta<T> type) throws ParseException, IOException {
563      try (ParserPipe pipe = createPipe(input)) {
564         return parseInner(pipe, type);
565      }
566   }
567
568   /**
569    * Same as {@link #parse(Object, ClassMeta)} except parses from a string and doesn't throw an {@link IOException}.
570    *
571    * <p>
572    * This is mostly an internal method used by the framework.
573    *
574    * @param <T> The class type of the object being created.
575    * @param input
576    *    The input.
577    *    See {@link #parse(Object, Type, Type...)} for details.
578    * @param type The object type to create.
579    * @return The parsed object.
580    * @throws ParseException Malformed input encountered.
581    */
582   public final <T> T parse(String input, ClassMeta<T> type) throws ParseException {
583      try (ParserPipe pipe = createPipe(input)) {
584         return parseInner(pipe, type);
585      } catch (IOException e) {
586         throw new ParseException(e); // Shouldn't happen.
587      }
588   }
589
590   /**
591    * Entry point for all parsing calls.
592    *
593    * <p>
594    * Calls the {@link #doParse(ParserPipe, ClassMeta)} implementation class and catches/re-wraps any exceptions
595    * thrown.
596    *
597    * @param pipe The parser input.
598    * @param type The class type of the object to create.
599    * @param <T> The class type of the object to create.
600    * @return The parsed object.
601    * @throws ParseException Malformed input encountered.
602    * @throws IOException Thrown by the underlying stream.
603    */
604   private <T> T parseInner(ParserPipe pipe, ClassMeta<T> type) throws ParseException, IOException {
605      if (type.isVoid())
606         return null;
607      try {
608         return doParse(pipe, type);
609      } catch (ParseException | IOException e) {
610         throw e;
611      } catch (StackOverflowError e) {
612         throw new ParseException(this, "Depth too deep.  Stack overflow occurred.");
613      } catch (Exception e) {
614         throw new ParseException(this, e, "Exception occurred.  exception={0}, message={1}.",
615            e.getClass().getSimpleName(), e.getLocalizedMessage());
616      } finally {
617         checkForWarnings();
618      }
619   }
620
621   /**
622    * Parses the contents of the specified reader and loads the results into the specified map.
623    *
624    * <p>
625    * Reader must contain something that serializes to a map (such as text containing a JSON object).
626    *
627    * <p>
628    * Used in the following locations:
629    * <ul class='spaced-list'>
630    *    <li>
631    *       The various character-based constructors in {@link OMap} (e.g.
632    *       {@link OMap#OMap(CharSequence,Parser)}).
633    * </ul>
634    *
635    * @param <K> The key class type.
636    * @param <V> The value class type.
637    * @param input The input.  See {@link #parse(Object, ClassMeta)} for supported input types.
638    * @param m The map being loaded.
639    * @param keyType The class type of the keys, or <jk>null</jk> to default to <code>String.<jk>class</jk></code>.
640    * @param valueType The class type of the values, or <jk>null</jk> to default to whatever is being parsed.
641    * @return The same map that was passed in to allow this method to be chained.
642    * @throws ParseException Malformed input encountered.
643    * @throws UnsupportedOperationException If not implemented.
644    */
645   public final <K,V> Map<K,V> parseIntoMap(Object input, Map<K,V> m, Type keyType, Type valueType) throws ParseException {
646      try (ParserPipe pipe = createPipe(input)) {
647         return doParseIntoMap(pipe, m, keyType, valueType);
648      } catch (ParseException e) {
649         throw e;
650      } catch (Exception e) {
651         throw new ParseException(this, e);
652      } finally {
653         checkForWarnings();
654      }
655   }
656
657   /**
658    * Implementation method.
659    *
660    * <p>
661    * Default implementation throws an {@link UnsupportedOperationException}.
662    *
663    * @param pipe The parser input.
664    * @param m The map being loaded.
665    * @param keyType The class type of the keys, or <jk>null</jk> to default to <code>String.<jk>class</jk></code>.
666    * @param valueType The class type of the values, or <jk>null</jk> to default to whatever is being parsed.
667    * @return The same map that was passed in to allow this method to be chained.
668    * @throws Exception If thrown from underlying stream, or if the input contains a syntax error or is malformed.
669    */
670   protected <K,V> Map<K,V> doParseIntoMap(ParserPipe pipe, Map<K,V> m, Type keyType, Type valueType) throws Exception {
671      throw new UnsupportedOperationException("Parser '"+getClass().getName()+"' does not support this method.");
672   }
673
674   /**
675    * Parses the contents of the specified reader and loads the results into the specified collection.
676    *
677    * <p>
678    * Used in the following locations:
679    * <ul class='spaced-list'>
680    *    <li>
681    *       The various character-based constructors in {@link OList} (e.g.
682    *       {@link OList#OList(CharSequence,Parser)}.
683    * </ul>
684    *
685    * @param <E> The element class type.
686    * @param input The input.  See {@link #parse(Object, ClassMeta)} for supported input types.
687    * @param c The collection being loaded.
688    * @param elementType The class type of the elements, or <jk>null</jk> to default to whatever is being parsed.
689    * @return The same collection that was passed in to allow this method to be chained.
690    * @throws ParseException Malformed input encountered.
691    * @throws UnsupportedOperationException If not implemented.
692    */
693   public final <E> Collection<E> parseIntoCollection(Object input, Collection<E> c, Type elementType) throws ParseException {
694      try (ParserPipe pipe = createPipe(input)) {
695         return doParseIntoCollection(pipe, c, elementType);
696      } catch (ParseException e) {
697         throw e;
698      } catch (StackOverflowError e) {
699         throw new ParseException(this, "Depth too deep.  Stack overflow occurred.");
700      } catch (IOException e) {
701         throw new ParseException(this, e, "I/O exception occurred.  exception={0}, message={1}.",
702            e.getClass().getSimpleName(), e.getLocalizedMessage());
703      } catch (Exception e) {
704         throw new ParseException(this, e, "Exception occurred.  exception={0}, message={1}.",
705            e.getClass().getSimpleName(), e.getLocalizedMessage());
706      } finally {
707         checkForWarnings();
708      }
709   }
710
711   /**
712    * Implementation method.
713    *
714    * <p>
715    * Default implementation throws an {@link UnsupportedOperationException}.
716    *
717    * @param pipe The parser input.
718    * @param c The collection being loaded.
719    * @param elementType The class type of the elements, or <jk>null</jk> to default to whatever is being parsed.
720    * @return The same collection that was passed in to allow this method to be chained.
721    * @throws Exception If thrown from underlying stream, or if the input contains a syntax error or is malformed.
722    */
723   protected <E> Collection<E> doParseIntoCollection(ParserPipe pipe, Collection<E> c, Type elementType) throws Exception {
724      throw new UnsupportedOperationException("Parser '"+getClass().getName()+"' does not support this method.");
725   }
726
727   /**
728    * Parses the specified array input with each entry in the object defined by the {@code argTypes}
729    * argument.
730    *
731    * <p>
732    * Used for converting arrays (e.g. <js>"[arg1,arg2,...]"</js>) into an {@code Object[]} that can be passed
733    * to the {@code Method.invoke(target, args)} method.
734    *
735    * <p>
736    * Used in the following locations:
737    * <ul class='spaced-list'>
738    *    <li>
739    *       Used to parse argument strings in the {@link PojoIntrospector#invokeMethod(Method, Reader)} method.
740    * </ul>
741    *
742    * @param input The input.  Subclasses can support different input types.
743    * @param argTypes Specifies the type of objects to create for each entry in the array.
744    * @return An array of parsed objects.
745    * @throws ParseException Malformed input encountered.
746    */
747   public final Object[] parseArgs(Object input, Type[] argTypes) throws ParseException {
748      try (ParserPipe pipe = createPipe(input)) {
749         return doParse(pipe, getArgsClassMeta(argTypes));
750      } catch (ParseException e) {
751         throw e;
752      } catch (StackOverflowError e) {
753         throw new ParseException(this, "Depth too deep.  Stack overflow occurred.");
754      } catch (IOException e) {
755         throw new ParseException(this, e, "I/O exception occurred.  exception={0}, message={1}.",
756            e.getClass().getSimpleName(), e.getLocalizedMessage());
757      } catch (Exception e) {
758         throw new ParseException(this, e, "Exception occurred.  exception={0}, message={1}.",
759            e.getClass().getSimpleName(), e.getLocalizedMessage());
760      } finally {
761         checkForWarnings();
762      }
763   }
764
765   /**
766    * Converts the specified string to the specified type.
767    *
768    * @param outer
769    *    The outer object if we're converting to an inner object that needs to be created within the context
770    *    of an outer object.
771    * @param s The string to convert.
772    * @param type The class type to convert the string to.
773    * @return The string converted as an object of the specified type.
774    * @param <T> The class type to convert the string to.
775    * @throws IOException Thrown by underlying stream.
776    * @throws ParseException Malformed input encountered.
777    * @throws ExecutableException Exception occurred on invoked constructor/method/field.
778    */
779   @SuppressWarnings({ "unchecked", "rawtypes" })
780   protected final <T> T convertAttrToType(Object outer, String s, ClassMeta<T> type) throws IOException, ParseException, ExecutableException {
781      if (s == null)
782         return null;
783
784      if (type == null)
785         type = (ClassMeta<T>)object();
786      PojoSwap swap = type.getSwap(this);
787      ClassMeta<?> sType = swap == null ? type : swap.getSwapClassMeta(this);
788
789      Object o = s;
790      if (sType.isChar())
791         o = parseCharacter(s);
792      else if (sType.isNumber())
793         o = parseNumber(s, (Class<? extends Number>)sType.getInnerClass());
794      else if (sType.isBoolean())
795         o = Boolean.parseBoolean(s);
796      else if (! (sType.isCharSequence() || sType.isObject())) {
797         if (sType.canCreateNewInstanceFromString(outer))
798            o = sType.newInstanceFromString(outer, s);
799         else
800            throw new ParseException(this, "Invalid conversion from string to class ''{0}''", type);
801      }
802
803      if (swap != null)
804         o = unswap(swap, o, type);
805
806      return (T)o;
807   }
808
809   /**
810    * Convenience method for calling the {@link ParentProperty @ParentProperty} method on the specified object if it
811    * exists.
812    *
813    * @param cm The class type of the object.
814    * @param o The object.
815    * @param parent The parent to set.
816    * @throws ExecutableException Exception occurred on invoked constructor/method/field.
817    */
818   protected static final void setParent(ClassMeta<?> cm, Object o, Object parent) throws ExecutableException {
819      Setter m = cm.getParentProperty();
820      if (m != null)
821         m.set(o, parent);
822   }
823
824   /**
825    * Convenience method for calling the {@link NameProperty @NameProperty} method on the specified object if it exists.
826    *
827    * @param cm The class type of the object.
828    * @param o The object.
829    * @param name The name to set.
830    * @throws ExecutableException Exception occurred on invoked constructor/method/field.
831    */
832   protected static final void setName(ClassMeta<?> cm, Object o, Object name) throws ExecutableException {
833      if (cm != null) {
834         Setter m = cm.getNameProperty();
835         if (m != null)
836            m.set(o, name);
837      }
838   }
839
840   /**
841    * Returns the listener associated with this session.
842    *
843    * @param c The listener class to cast to.
844    * @return The listener associated with this session, or <jk>null</jk> if there is no listener.
845    */
846   @SuppressWarnings("unchecked")
847   public <T extends ParserListener> T getListener(Class<T> c) {
848      return (T)listener;
849   }
850
851   /**
852    * The {@link #createPipe(Object)} method should call this method to set the pipe for debugging purposes.
853    *
854    * @param pipe The pipe created for this session.
855    * @return The same pipe.
856    */
857   protected ParserPipe setPipe(ParserPipe pipe) {
858      this.pipe = pipe;
859      return pipe;
860   }
861
862   /**
863    * Returns the current position into the reader or input stream.
864    *
865    * @return
866    *    The current position into the reader or input stream.
867    *    <br>Never <jk>null</jk>.
868    */
869   public Position getPosition() {
870      if (mark.line != -1 || mark.column != -1 || mark.position != -1)
871         return mark;
872      if (pipe == null)
873         return Position.UNKNOWN;
874      return pipe.getPosition();
875   }
876
877   /**
878    * Marks the current position.
879    */
880   protected void mark() {
881      if (pipe != null) {
882         Position p = pipe.getPosition();
883         mark.line = p.line;
884         mark.column = p.column;
885         mark.position = p.position;
886      }
887   }
888
889   /**
890    * Unmarks the current position.
891    */
892   protected void unmark() {
893      mark.line = -1;
894      mark.column = -1;
895      mark.position = -1;
896   }
897
898   /**
899    * Returns the input as a string.
900    *
901    * <p>
902    * This always returns a value for input of type {@link CharSequence}.
903    * <br>For other input types, use {@link Context#CONTEXT_debug} setting to enable caching to a string
904    * before parsing so that this method returns the input.
905    *
906    * @return The input as a string, or <jk>null</jk> if no pipe has been created or we're reading from an uncached reader or input stream source.
907    */
908   public String getInputAsString() {
909      return pipe == null ? null : pipe.getInputAsString();
910   }
911
912   /**
913    * Invokes the specified swap on the specified object.
914    *
915    * @param swap The swap to invoke.
916    * @param o The input object.
917    * @param eType The expected type.
918    * @return The swapped object.
919    * @throws ParseException If swap method threw an exception.
920    */
921   @SuppressWarnings({ "rawtypes", "unchecked" })
922   protected Object unswap(PojoSwap swap, Object o, ClassMeta<?> eType) throws ParseException {
923      try {
924         return swap.unswap(this, o, eType);
925      } catch (Exception e) {
926         throw new ParseException(e);
927      }
928   }
929
930   //-----------------------------------------------------------------------------------------------------------------
931   // Properties
932   //-----------------------------------------------------------------------------------------------------------------
933
934   /**
935    * Configuration property:  Auto-close streams.
936    *
937    * @see Parser#PARSER_autoCloseStreams
938    * @return
939    *    <jk>true</jk> if <l>InputStreams</l> and <l>Readers</l> passed into parsers will be closed
940    *    after parsing is complete.
941    */
942   protected final boolean isAutoCloseStreams() {
943      return ctx.isAutoCloseStreams();
944   }
945
946   /**
947    * Configuration property:  Debug output lines.
948    *
949    * @see Parser#PARSER_debugOutputLines
950    * @return
951    *    The number of lines of input before and after the error location to be printed as part of the exception message.
952    */
953   protected final int getDebugOutputLines() {
954      return ctx.getDebugOutputLines();
955   }
956
957   /**
958    * Returns the listener associated with this session.
959    *
960    * @return The listener associated with this session, or <jk>null</jk> if there is no listener.
961    */
962   public ParserListener getListener() {
963      return listener;
964   }
965
966   /**
967    * Configuration property:  Strict mode.
968    *
969    * @see Parser#PARSER_strict
970    * @return
971    *    <jk>true</jk> if strict mode for the parser is enabled.
972    */
973   protected final boolean isStrict() {
974      return ctx.isStrict();
975   }
976
977   /**
978    * Configuration property:  Trim parsed strings.
979    *
980    * @see Parser#PARSER_trimStrings
981    * @return
982    *    <jk>true</jk> if string values will be trimmed of whitespace using {@link String#trim()} before being added to
983    *    the POJO.
984    */
985   protected final boolean isTrimStrings() {
986      return ctx.isTrimStrings();
987   }
988
989   /**
990    * Configuration property:  Unbuffered.
991    *
992    * @see Parser#PARSER_unbuffered
993    * @return
994    *    <jk>true</jk> if parsers don't use internal buffering during parsing.
995    */
996   protected final boolean isUnbuffered() {
997      return ctx.isUnbuffered();
998   }
999
1000   //-----------------------------------------------------------------------------------------------------------------
1001   // Other methods
1002   //-----------------------------------------------------------------------------------------------------------------
1003
1004   /**
1005    * Configuration property:  Parser listener.
1006    *
1007    * @see Parser#PARSER_listener
1008    * @return
1009    *    Class used to listen for errors and warnings that occur during parsing.
1010    */
1011   protected final Class<? extends ParserListener> getListenerClass() {
1012      return ctx.getListener();
1013   }
1014
1015   @Override /* Session */
1016   public OMap toMap() {
1017      return super.toMap()
1018         .a("ParserSession", new DefaultFilteringOMap()
1019            .a("javaMethod", javaMethod)
1020            .a("listener", listener)
1021            .a("outer", outer)
1022         );
1023   }
1024}