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