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