001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.json;
018
019import static org.apache.juneau.commons.utils.AssertionUtils.*;
020import static org.apache.juneau.commons.utils.Utils.*;
021
022import java.lang.annotation.*;
023import java.nio.charset.*;
024import java.util.*;
025import java.util.concurrent.*;
026
027import org.apache.juneau.*;
028import org.apache.juneau.collections.*;
029import org.apache.juneau.commons.collections.*;
030import org.apache.juneau.commons.function.*;
031import org.apache.juneau.commons.reflect.*;
032import org.apache.juneau.parser.*;
033
034/**
035 * Parses any valid JSON text into a POJO model.
036 *
037 * <h5 class='topic'>Media types</h5>
038 * <p>
039 * Handles <c>Content-Type</c> types:  <bc>application/json, text/json</bc>
040 *
041 * <h5 class='topic'>Description</h5>
042 * <p>
043 * This parser uses a state machine, which makes it very fast and efficient.  It parses JSON in about 70% of the
044 * time that it takes the built-in Java DOM parsers to parse equivalent XML.
045 *
046 * <p>
047 * This parser handles all valid JSON syntax.
048 * In addition, when strict mode is disable, the parser also handles the following:
049 * <ul class='spaced-list'>
050 *    <li>
051 *       Javascript comments (both {@code /*} and {@code //}) are ignored.
052 *    <li>
053 *       Both single and double quoted strings.
054 *    <li>
055 *       Automatically joins concatenated strings (e.g. <code><js>"aaa"</js> + <js>'bbb'</js></code>).
056 *    <li>
057 *       Unquoted attributes and values.
058 * </ul>
059 *
060 * <p>
061 * Also handles negative, decimal, hexadecimal, octal, and double numbers, including exponential notation.
062 *
063 * <p>
064 * This parser handles the following input, and automatically returns the corresponding Java class.
065 * <ul class='spaced-list'>
066 *    <li>
067 *       JSON objects (<js>"{...}"</js>) are converted to {@link JsonMap JsonMaps}.
068 *       <b>Note:</b>  If a <code><xa>_type</xa>=<xs>'xxx'</xs></code> attribute is specified on the object, then an
069 *       attempt is made to convert the object to an instance of the specified Java bean class.
070 *       See the {@link org.apache.juneau.BeanContext.Builder#typePropertyName(String)} setting for more information about parsing
071 *       beans from JSON.
072 *    <li>
073 *       JSON arrays (<js>"[...]"</js>) are converted to {@link JsonList JsonLists}.
074 *    <li>
075 *       JSON string literals (<js>"'xyz'"</js>) are converted to {@link String Strings}.
076 *    <li>
077 *       JSON numbers (<js>"123"</js>, including octal/hexadecimal/exponential notation) are converted to
078 *       {@link Integer Integers}, {@link Long Longs}, {@link Float Floats}, or {@link Double Doubles} depending on
079 *       whether the number is decimal, and the size of the number.
080 *    <li>
081 *       JSON booleans (<js>"false"</js>) are converted to {@link Boolean Booleans}.
082 *    <li>
083 *       JSON nulls (<js>"null"</js>) are converted to <jk>null</jk>.
084 *    <li>
085 *       Input consisting of only whitespace or JSON comments are converted to <jk>null</jk>.
086 * </ul>
087 *
088 * <p>
089 * Input can be any of the following:
090 * <ul class='spaced-list'>
091 *    <li>
092 *       <js>"{...}"</js> - Converted to an {@link JsonMap} or an instance of a Java bean if a <xa>_type</xa>
093 *       attribute is present.
094 *    <li>
095 *       <js>"[...]"</js> - Converted to an {@link JsonList}.
096 *    <li>
097 *       <js>"123..."</js> - Converted to a {@link Number} (either {@link Integer}, {@link Long}, {@link Float},
098 *       or {@link Double}).
099 *    <li>
100 *       <js>"true"</js>/<js>"false"</js> - Converted to a {@link Boolean}.
101 *    <li>
102 *       <js>"null"</js> - Returns <jk>null</jk>.
103 *    <li>
104 *       <js>"'xxx'"</js> - Converted to a {@link String}.
105 *    <li>
106 *       <js>"\"xxx\""</js> - Converted to a {@link String}.
107 *    <li>
108 *       <js>"'xxx' + \"yyy\""</js> - Converted to a concatenated {@link String}.
109 * </ul>
110 *
111 * <p>
112 * TIP:  If you know you're parsing a JSON object or array, it can be easier to parse it using the
113 * {@link JsonMap#JsonMap(CharSequence) JsonMap(CharSequence)} or {@link JsonList#JsonList(CharSequence)
114 * JsonList(CharSequence)} constructors instead of using this class.
115 * The end result should be the same.
116 *
117 * <h5 class='section'>Notes:</h5><ul>
118 *    <li class='note'>This class is thread safe and reusable.
119 * </ul>
120 *
121 * <h5 class='section'>See Also:</h5><ul>
122 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JsonBasics">JSON Basics</a>
123
124 * </ul>
125 */
126public class JsonParser extends ReaderParser implements JsonMetaProvider {
127   /**
128    * Builder class.
129    */
130   public static class Builder extends ReaderParser.Builder {
131
132      private static final Cache<HashKey,JsonParser> CACHE = Cache.of(HashKey.class, JsonParser.class).build();
133
134      private boolean validateEnd;
135
136      /**
137       * Constructor, default settings.
138       */
139      protected Builder() {
140         consumes("application/json,text/json");
141         validateEnd = env("JsonParser.validateEnd", false);
142      }
143
144      /**
145       * Copy constructor.
146       *
147       * @param copyFrom The builder to copy from.
148       *    <br>Cannot be <jk>null</jk>.
149       */
150      protected Builder(Builder copyFrom) {
151         super(assertArgNotNull("copyFrom", copyFrom));
152         validateEnd = copyFrom.validateEnd;
153      }
154
155      /**
156       * Copy constructor.
157       *
158       * @param copyFrom The bean to copy from.
159       *    <br>Cannot be <jk>null</jk>.
160       */
161      protected Builder(JsonParser copyFrom) {
162         super(assertArgNotNull("copyFrom", copyFrom));
163         validateEnd = copyFrom.validateEnd;
164      }
165
166      @Override /* Overridden from Builder */
167      public Builder annotations(Annotation...values) {
168         super.annotations(values);
169         return this;
170      }
171
172      @Override /* Overridden from Builder */
173      public Builder apply(AnnotationWorkList work) {
174         super.apply(work);
175         return this;
176      }
177
178      @Override /* Overridden from Builder */
179      public Builder applyAnnotations(Class<?>...from) {
180         super.applyAnnotations(from);
181         return this;
182      }
183
184      @Override /* Overridden from Builder */
185      public Builder applyAnnotations(Object...from) {
186         super.applyAnnotations(from);
187         return this;
188      }
189
190      @Override /* Overridden from Builder */
191      public Builder autoCloseStreams() {
192         super.autoCloseStreams();
193         return this;
194      }
195
196      @Override /* Overridden from Builder */
197      public Builder autoCloseStreams(boolean value) {
198         super.autoCloseStreams(value);
199         return this;
200      }
201
202      @Override /* Overridden from Builder */
203      public Builder beanClassVisibility(Visibility value) {
204         super.beanClassVisibility(value);
205         return this;
206      }
207
208      @Override /* Overridden from Builder */
209      public Builder beanConstructorVisibility(Visibility value) {
210         super.beanConstructorVisibility(value);
211         return this;
212      }
213
214      @Override /* Overridden from Builder */
215      public Builder beanContext(BeanContext value) {
216         super.beanContext(value);
217         return this;
218      }
219
220      @Override /* Overridden from Builder */
221      public Builder beanContext(BeanContext.Builder value) {
222         super.beanContext(value);
223         return this;
224      }
225
226      @Override /* Overridden from Builder */
227      public Builder beanDictionary(java.lang.Class<?>...values) {
228         super.beanDictionary(values);
229         return this;
230      }
231
232      @Override /* Overridden from Builder */
233      public Builder beanFieldVisibility(Visibility value) {
234         super.beanFieldVisibility(value);
235         return this;
236      }
237
238      @Override /* Overridden from Builder */
239      public Builder beanInterceptor(Class<?> on, Class<? extends org.apache.juneau.swap.BeanInterceptor<?>> value) {
240         super.beanInterceptor(on, value);
241         return this;
242      }
243
244      @Override /* Overridden from Builder */
245      public Builder beanMapPutReturnsOldValue() {
246         super.beanMapPutReturnsOldValue();
247         return this;
248      }
249
250      @Override /* Overridden from Builder */
251      public Builder beanMethodVisibility(Visibility value) {
252         super.beanMethodVisibility(value);
253         return this;
254      }
255
256      @Override /* Overridden from Builder */
257      public Builder beanProperties(Class<?> beanClass, String properties) {
258         super.beanProperties(beanClass, properties);
259         return this;
260      }
261
262      @Override /* Overridden from Builder */
263      public Builder beanProperties(Map<String,Object> values) {
264         super.beanProperties(values);
265         return this;
266      }
267
268      @Override /* Overridden from Builder */
269      public Builder beanProperties(String beanClassName, String properties) {
270         super.beanProperties(beanClassName, properties);
271         return this;
272      }
273
274      @Override /* Overridden from Builder */
275      public Builder beanPropertiesExcludes(Class<?> beanClass, String properties) {
276         super.beanPropertiesExcludes(beanClass, properties);
277         return this;
278      }
279
280      @Override /* Overridden from Builder */
281      public Builder beanPropertiesExcludes(Map<String,Object> values) {
282         super.beanPropertiesExcludes(values);
283         return this;
284      }
285
286      @Override /* Overridden from Builder */
287      public Builder beanPropertiesExcludes(String beanClassName, String properties) {
288         super.beanPropertiesExcludes(beanClassName, properties);
289         return this;
290      }
291
292      @Override /* Overridden from Builder */
293      public Builder beanPropertiesReadOnly(Class<?> beanClass, String properties) {
294         super.beanPropertiesReadOnly(beanClass, properties);
295         return this;
296      }
297
298      @Override /* Overridden from Builder */
299      public Builder beanPropertiesReadOnly(Map<String,Object> values) {
300         super.beanPropertiesReadOnly(values);
301         return this;
302      }
303
304      @Override /* Overridden from Builder */
305      public Builder beanPropertiesReadOnly(String beanClassName, String properties) {
306         super.beanPropertiesReadOnly(beanClassName, properties);
307         return this;
308      }
309
310      @Override /* Overridden from Builder */
311      public Builder beanPropertiesWriteOnly(Class<?> beanClass, String properties) {
312         super.beanPropertiesWriteOnly(beanClass, properties);
313         return this;
314      }
315
316      @Override /* Overridden from Builder */
317      public Builder beanPropertiesWriteOnly(Map<String,Object> values) {
318         super.beanPropertiesWriteOnly(values);
319         return this;
320      }
321
322      @Override /* Overridden from Builder */
323      public Builder beanPropertiesWriteOnly(String beanClassName, String properties) {
324         super.beanPropertiesWriteOnly(beanClassName, properties);
325         return this;
326      }
327
328      @Override /* Overridden from Builder */
329      public Builder beansRequireDefaultConstructor() {
330         super.beansRequireDefaultConstructor();
331         return this;
332      }
333
334      @Override /* Overridden from Builder */
335      public Builder beansRequireSerializable() {
336         super.beansRequireSerializable();
337         return this;
338      }
339
340      @Override /* Overridden from Builder */
341      public Builder beansRequireSettersForGetters() {
342         super.beansRequireSettersForGetters();
343         return this;
344      }
345
346      @Override /* Overridden from Context.Builder */
347      public JsonParser build() {
348         return cache(CACHE).build(JsonParser.class);
349      }
350
351      @Override /* Overridden from Builder */
352      public Builder cache(Cache<HashKey,? extends org.apache.juneau.Context> value) {
353         super.cache(value);
354         return this;
355      }
356
357      @Override /* Overridden from Builder */
358      public Builder consumes(String value) {
359         super.consumes(value);
360         return this;
361      }
362
363      @Override /* Overridden from Context.Builder */
364      public Builder copy() {
365         return new Builder(this);
366      }
367
368      @Override /* Overridden from Builder */
369      public Builder debug() {
370         super.debug();
371         return this;
372      }
373
374      @Override /* Overridden from Builder */
375      public Builder debug(boolean value) {
376         super.debug(value);
377         return this;
378      }
379
380      @Override /* Overridden from Builder */
381      public Builder debugOutputLines(int value) {
382         super.debugOutputLines(value);
383         return this;
384      }
385
386      @Override /* Overridden from Builder */
387      public Builder dictionaryOn(Class<?> on, java.lang.Class<?>...values) {
388         super.dictionaryOn(on, values);
389         return this;
390      }
391
392      @Override /* Overridden from Builder */
393      public Builder disableBeansRequireSomeProperties() {
394         super.disableBeansRequireSomeProperties();
395         return this;
396      }
397
398      @Override /* Overridden from Builder */
399      public Builder disableIgnoreMissingSetters() {
400         super.disableIgnoreMissingSetters();
401         return this;
402      }
403
404      @Override /* Overridden from Builder */
405      public Builder disableIgnoreTransientFields() {
406         super.disableIgnoreTransientFields();
407         return this;
408      }
409
410      @Override /* Overridden from Builder */
411      public Builder disableIgnoreUnknownNullBeanProperties() {
412         super.disableIgnoreUnknownNullBeanProperties();
413         return this;
414      }
415
416      @Override /* Overridden from Builder */
417      public Builder disableInterfaceProxies() {
418         super.disableInterfaceProxies();
419         return this;
420      }
421
422      @Override /* Overridden from Builder */
423      public <T> Builder example(Class<T> pojoClass, String json) {
424         super.example(pojoClass, json);
425         return this;
426      }
427
428      @Override /* Overridden from Builder */
429      public <T> Builder example(Class<T> pojoClass, T o) {
430         super.example(pojoClass, o);
431         return this;
432      }
433
434      @Override /* Overridden from Builder */
435      public Builder fileCharset(Charset value) {
436         super.fileCharset(value);
437         return this;
438      }
439
440      @Override /* Overridden from Builder */
441      public Builder findFluentSetters() {
442         super.findFluentSetters();
443         return this;
444      }
445
446      @Override /* Overridden from Builder */
447      public Builder findFluentSetters(Class<?> on) {
448         super.findFluentSetters(on);
449         return this;
450      }
451
452      @Override /* Overridden from Context.Builder */
453      public HashKey hashKey() {
454         return HashKey.of(super.hashKey(), validateEnd);
455      }
456
457      @Override /* Overridden from Builder */
458      public Builder ignoreInvocationExceptionsOnGetters() {
459         super.ignoreInvocationExceptionsOnGetters();
460         return this;
461      }
462
463      @Override /* Overridden from Builder */
464      public Builder ignoreInvocationExceptionsOnSetters() {
465         super.ignoreInvocationExceptionsOnSetters();
466         return this;
467      }
468
469      @Override /* Overridden from Builder */
470      public Builder ignoreUnknownBeanProperties() {
471         super.ignoreUnknownBeanProperties();
472         return this;
473      }
474
475      @Override /* Overridden from Builder */
476      public Builder ignoreUnknownEnumValues() {
477         super.ignoreUnknownEnumValues();
478         return this;
479      }
480
481      @Override /* Overridden from Builder */
482      public Builder impl(Context value) {
483         super.impl(value);
484         return this;
485      }
486
487      @Override /* Overridden from Builder */
488      public Builder implClass(Class<?> interfaceClass, Class<?> implClass) {
489         super.implClass(interfaceClass, implClass);
490         return this;
491      }
492
493      @Override /* Overridden from Builder */
494      public Builder implClasses(Map<Class<?>,Class<?>> values) {
495         super.implClasses(values);
496         return this;
497      }
498
499      @Override /* Overridden from Builder */
500      public Builder interfaceClass(Class<?> on, Class<?> value) {
501         super.interfaceClass(on, value);
502         return this;
503      }
504
505      @Override /* Overridden from Builder */
506      public Builder interfaces(java.lang.Class<?>...value) {
507         super.interfaces(value);
508         return this;
509      }
510
511      @Override /* Overridden from Builder */
512      public Builder listener(Class<? extends org.apache.juneau.parser.ParserListener> value) {
513         super.listener(value);
514         return this;
515      }
516
517      @Override /* Overridden from Builder */
518      public Builder locale(Locale value) {
519         super.locale(value);
520         return this;
521      }
522
523      @Override /* Overridden from Builder */
524      public Builder mediaType(MediaType value) {
525         super.mediaType(value);
526         return this;
527      }
528
529      @Override /* Overridden from Builder */
530      public Builder notBeanClasses(java.lang.Class<?>...values) {
531         super.notBeanClasses(values);
532         return this;
533      }
534
535      @Override /* Overridden from Builder */
536      public Builder notBeanPackages(String...values) {
537         super.notBeanPackages(values);
538         return this;
539      }
540
541      @Override /* Overridden from Builder */
542      public Builder propertyNamer(Class<?> on, Class<? extends org.apache.juneau.PropertyNamer> value) {
543         super.propertyNamer(on, value);
544         return this;
545      }
546
547      @Override /* Overridden from Builder */
548      public Builder propertyNamer(Class<? extends org.apache.juneau.PropertyNamer> value) {
549         super.propertyNamer(value);
550         return this;
551      }
552
553      @Override /* Overridden from Builder */
554      public Builder sortProperties() {
555         super.sortProperties();
556         return this;
557      }
558
559      @Override /* Overridden from Builder */
560      public Builder sortProperties(java.lang.Class<?>...on) {
561         super.sortProperties(on);
562         return this;
563      }
564
565      @Override /* Overridden from Builder */
566      public Builder stopClass(Class<?> on, Class<?> value) {
567         super.stopClass(on, value);
568         return this;
569      }
570
571      @Override /* Overridden from Builder */
572      public Builder streamCharset(Charset value) {
573         super.streamCharset(value);
574         return this;
575      }
576
577      @Override /* Overridden from Builder */
578      public Builder strict() {
579         super.strict();
580         return this;
581      }
582
583      @Override /* Overridden from Builder */
584      public Builder strict(boolean value) {
585         super.strict(value);
586         return this;
587      }
588
589      @Override /* Overridden from Builder */
590      public <T,S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction) {
591         super.swap(normalClass, swappedClass, swapFunction);
592         return this;
593      }
594
595      @Override /* Overridden from Builder */
596      public <T,S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction, ThrowingFunction<S,T> unswapFunction) {
597         super.swap(normalClass, swappedClass, swapFunction, unswapFunction);
598         return this;
599      }
600
601      @Override /* Overridden from Builder */
602      public Builder swaps(Class<?>...values) {
603         super.swaps(values);
604         return this;
605      }
606
607      @Override /* Overridden from Builder */
608      public Builder swaps(Object...values) {
609         super.swaps(values);
610         return this;
611      }
612
613      @Override /* Overridden from Builder */
614      public Builder timeZone(TimeZone value) {
615         super.timeZone(value);
616         return this;
617      }
618
619      @Override /* Overridden from Builder */
620      public Builder trimStrings() {
621         super.trimStrings();
622         return this;
623      }
624
625      @Override /* Overridden from Builder */
626      public Builder trimStrings(boolean value) {
627         super.trimStrings(value);
628         return this;
629      }
630
631      @Override /* Overridden from Builder */
632      public Builder type(Class<? extends org.apache.juneau.Context> value) {
633         super.type(value);
634         return this;
635      }
636
637      @Override /* Overridden from Builder */
638      public Builder typeName(Class<?> on, String value) {
639         super.typeName(on, value);
640         return this;
641      }
642
643      @Override /* Overridden from Builder */
644      public Builder typePropertyName(Class<?> on, String value) {
645         super.typePropertyName(on, value);
646         return this;
647      }
648
649      @Override /* Overridden from Builder */
650      public Builder typePropertyName(String value) {
651         super.typePropertyName(value);
652         return this;
653      }
654
655      @Override /* Overridden from Builder */
656      public Builder unbuffered() {
657         super.unbuffered();
658         return this;
659      }
660
661      @Override /* Overridden from Builder */
662      public Builder unbuffered(boolean value) {
663         super.unbuffered(value);
664         return this;
665      }
666
667      @Override /* Overridden from Builder */
668      public Builder useEnumNames() {
669         super.useEnumNames();
670         return this;
671      }
672
673      @Override /* Overridden from Builder */
674      public Builder useJavaBeanIntrospector() {
675         super.useJavaBeanIntrospector();
676         return this;
677      }
678
679      /**
680       * Validate end.
681       *
682       * <p>
683       * When enabled, after parsing a POJO from the input, verifies that the remaining input in
684       * the stream consists of only comments or whitespace.
685       *
686       * <h5 class='section'>Example:</h5>
687       * <p class='bjava'>
688       *    <jc>// Create a parser that validates that there's no garbage at the end of the input.</jc>
689       *    ReaderParser <jv>parser</jv> = JsonParser.
690       *       .<jsm>create</jsm>()
691       *       .validateEnd()
692       *       .build();
693       *
694       *    <jc>// Should fail because input has multiple POJOs.</jc>
695       *    String <jv>json</jv> = <js>"{foo:'bar'}{baz:'qux'}"</js>;
696       *    MyBean <jv>myBean</jv> =<jv>parser</jv>.parse(<jv>json</jv>, MyBean.<jk>class</jk>);
697       * </p>
698       *
699       * @return This object.
700       */
701      public Builder validateEnd() {
702         return validateEnd(true);
703      }
704
705      /**
706       * Same as {@link #validateEnd()} but allows you to explicitly specify the value.
707       *
708       * @param value The value for this setting.
709       * @return This object.
710       */
711      public Builder validateEnd(boolean value) {
712         validateEnd = value;
713         return this;
714      }
715   }
716
717   /** Default parser, strict mode. */
718   public static class Strict extends JsonParser {
719
720      /**
721       * Constructor.
722       *
723       * @param builder The builder for this object.
724       */
725      public Strict(Builder builder) {
726         super(builder.strict().validateEnd());
727      }
728   }
729
730   /** Default parser, all default settings.*/
731   public static final JsonParser DEFAULT = new JsonParser(create());
732   /** Default parser, all default settings.*/
733   public static final JsonParser DEFAULT_STRICT = new JsonParser.Strict(create());
734
735   /**
736    * Creates a new builder for this object.
737    *
738    * @return A new builder.
739    */
740   public static Builder create() {
741      return new Builder();
742   }
743
744   protected final boolean validateEnd;
745
746   private final Map<BeanPropertyMeta,JsonBeanPropertyMeta> jsonBeanPropertyMetas = new ConcurrentHashMap<>();
747   private final Map<ClassMeta<?>,JsonClassMeta> jsonClassMetas = new ConcurrentHashMap<>();
748
749   /**
750    * Constructor.
751    *
752    * @param builder The builder for this object.
753    */
754   public JsonParser(Builder builder) {
755      super(builder);
756      validateEnd = builder.validateEnd;
757   }
758
759   @Override /* Overridden from Context */
760   public Builder copy() {
761      return new Builder(this);
762   }
763
764   @Override /* Overridden from Context */
765   public JsonParserSession.Builder createSession() {
766      return JsonParserSession.create(this);
767   }
768
769   @Override /* Overridden from JsonMetaProvider */
770   public JsonBeanPropertyMeta getJsonBeanPropertyMeta(BeanPropertyMeta bpm) {
771      if (bpm == null)
772         return JsonBeanPropertyMeta.DEFAULT;
773      JsonBeanPropertyMeta m = jsonBeanPropertyMetas.get(bpm);
774      if (m == null) {
775         m = new JsonBeanPropertyMeta(bpm.getDelegateFor(), this);
776         jsonBeanPropertyMetas.put(bpm, m);
777      }
778      return m;
779   }
780
781   @Override /* Overridden from JsonMetaProvider */
782   public JsonClassMeta getJsonClassMeta(ClassMeta<?> cm) {
783      JsonClassMeta m = jsonClassMetas.get(cm);
784      if (m == null) {
785         m = new JsonClassMeta(cm, this);
786         jsonClassMetas.put(cm, m);
787      }
788      return m;
789   }
790
791   @Override /* Overridden from Context */
792   public JsonParserSession getSession() { return createSession().build(); }
793
794   /**
795    * Validate end.
796    *
797    * @see Builder#validateEnd()
798    * @return
799    *    <jk>true</jk> if after parsing a POJO from the input, verifies that the remaining input in
800    *    the stream consists of only comments or whitespace.
801    */
802   protected final boolean isValidateEnd() { return validateEnd; }
803}