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.xml;
018
019import static org.apache.juneau.collections.JsonMap.*;
020import static org.apache.juneau.common.utils.ThrowableUtils.*;
021import static org.apache.juneau.common.utils.Utils.*;
022
023import java.lang.annotation.*;
024import java.nio.charset.*;
025import java.util.*;
026import java.util.concurrent.*;
027
028import javax.xml.stream.*;
029import javax.xml.stream.util.*;
030
031import org.apache.juneau.*;
032import org.apache.juneau.collections.*;
033import org.apache.juneau.internal.*;
034import org.apache.juneau.parser.*;
035import org.apache.juneau.utils.*;
036
037/**
038 * Parses text generated by the {@link XmlSerializer} class back into a POJO model.
039 *
040 * <h5 class='topic'>Media types</h5>
041 * <p>
042 * Handles <c>Content-Type</c> types:  <bc>text/xml</bc>
043 *
044 * <h5 class='topic'>Description</h5>
045 * <p>
046 * See the {@link XmlSerializer} class for a description of Juneau-generated XML.
047 *
048 * <h5 class='section'>Notes:</h5><ul>
049 *    <li class='note'>This class is thread safe and reusable.
050 * </ul>
051 *
052 * <h5 class='section'>See Also:</h5><ul>
053 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/XmlBasics">XML Basics</a>
054
055 * </ul>
056 */
057public class XmlParser extends ReaderParser implements XmlMetaProvider {
058
059   //-------------------------------------------------------------------------------------------------------------------
060   // Static
061   //-------------------------------------------------------------------------------------------------------------------
062
063   /** Default parser, all default settings.*/
064   public static final XmlParser DEFAULT = new XmlParser(create());
065
066   /**
067    * Creates a new builder for this object.
068    *
069    * @return A new builder.
070    */
071   public static Builder create() {
072      return new Builder();
073   }
074
075   //-------------------------------------------------------------------------------------------------------------------
076   // Builder
077   //-------------------------------------------------------------------------------------------------------------------
078
079   /**
080    * Builder class.
081    */
082   public static class Builder extends ReaderParser.Builder {
083
084      private static final Cache<HashKey,XmlParser> CACHE = Cache.of(HashKey.class, XmlParser.class).build();
085
086      boolean preserveRootElement, validating;
087      Class<? extends XMLEventAllocator> eventAllocator;
088      Class<? extends XMLReporter> reporter;
089      Class<? extends XMLResolver> resolver;
090
091      /**
092       * Constructor, default settings.
093       */
094      protected Builder() {
095         consumes("text/xml,application/xml");
096         preserveRootElement = env("XmlParser.preserveRootElement", false);
097         validating = env("XmlParser.validating", false);
098         eventAllocator = null;
099         reporter = null;
100         resolver = null;
101      }
102
103      /**
104       * Copy constructor.
105       *
106       * @param copyFrom The bean to copy from.
107       */
108      protected Builder(XmlParser copyFrom) {
109         super(copyFrom);
110         preserveRootElement = copyFrom.preserveRootElement;
111         validating = copyFrom.validating;
112         eventAllocator = copyFrom.eventAllocator;
113         reporter = copyFrom.reporter;
114         resolver = copyFrom.resolver;
115      }
116
117      /**
118       * Copy constructor.
119       *
120       * @param copyFrom The builder to copy from.
121       */
122      protected Builder(Builder copyFrom) {
123         super(copyFrom);
124         preserveRootElement = copyFrom.preserveRootElement;
125         validating = copyFrom.validating;
126         eventAllocator = copyFrom.eventAllocator;
127         reporter = copyFrom.reporter;
128         resolver = copyFrom.resolver;
129      }
130
131      @Override /* Context.Builder */
132      public Builder copy() {
133         return new Builder(this);
134      }
135
136      @Override /* Context.Builder */
137      public XmlParser build() {
138         return cache(CACHE).build(XmlParser.class);
139      }
140
141      @Override /* Context.Builder */
142      public HashKey hashKey() {
143         return HashKey.of(
144            super.hashKey(),
145            preserveRootElement,
146            validating,
147            eventAllocator,
148            reporter,
149            resolver
150         );
151      }
152
153      //-----------------------------------------------------------------------------------------------------------------
154      // Properties
155      //-----------------------------------------------------------------------------------------------------------------
156
157      /**
158       * XML event allocator.
159       *
160       * <p>
161       * Associates an {@link XMLEventAllocator} with this parser.
162       *
163       * @param value The new value for this property.
164       * @return This object.
165       */
166      public Builder eventAllocator(Class<? extends XMLEventAllocator> value) {
167         eventAllocator = value;
168         return this;
169      }
170
171      /**
172       * Preserve root element during generalized parsing.
173       *
174       * <p>
175       * When enabled, when parsing into a generic {@link JsonMap}, the map will contain a single entry whose key
176       * is the root element name.
177       *
178       * <h5 class='section'>Example:</h5>
179       * <p class='bjava'>
180       *    <jc>// Parser with preserve-root-element.</jc>
181       *    ReaderParser <jv>parser1</jv> = XmlParser
182       *       .<jsm>create</jsm>()
183       *       .preserveRootElement()
184       *       .build();
185       *
186       *    <jc>// Parser without preserve-root-element (the default behavior).</jc>
187       *    ReaderParser <jv>parser2</jv> = XmlParser
188       *       .<jsm>create</jsm>()
189       *       .build();
190       *
191       *    String <jv>xml</jv> = <js>"&lt;root&gt;&lt;a&gt;foobar&lt;/a&gt;&lt;/root&gt;"</js>;
192       *
193       *    <jc>// Produces:  "{ root: { a:'foobar' }}"</jc>
194       *    JsonMap <jv>map1</jv> = <jv>parser1</jv>.parse(<jv>xml</jv>, JsonMap.<jk>class</jk>);
195       *
196       *    <jc>// Produces:  "{ a:'foobar' }"</jc>
197       *    JsonMap <jv>map2</jv> = <jv>parser2</jv>.parse(<jv>xml</jv>, JsonMap.<jk>class</jk>);
198       * </p>
199       *
200       * @return This object.
201       */
202      public Builder preserveRootElement() {
203         return preserveRootElement(true);
204      }
205
206      /**
207       * Same as {@link #preserveRootElement()} but allows you to explicitly specify the value.
208       *
209       * @param value The value for this setting.
210       * @return This object.
211       */
212      public Builder preserveRootElement(boolean value) {
213         preserveRootElement = value;
214         return this;
215      }
216
217      /**
218       * XML reporter.
219       *
220       * <p>
221       * Associates an {@link XMLReporter} with this parser.
222       *
223       * @param value The new value for this property.
224       * @return This object.
225       */
226      public Builder reporter(Class<? extends XMLReporter> value) {
227         reporter = value;
228         return this;
229      }
230
231      /**
232       * XML resolver.
233       *
234       * <p>
235       * Associates an {@link XMLResolver} with this parser.
236       *
237       * @param value The new value for this property.
238       * @return This object.
239       */
240      public Builder resolver(Class<? extends XMLResolver> value) {
241         resolver = value;
242         return this;
243      }
244
245      /**
246       * Enable validation.
247       *
248       * <p>
249       * If <jk>true</jk>, XML document will be validated.
250       *
251       * <p>
252       * See {@link XMLInputFactory#IS_VALIDATING} for more info.
253       *
254       * @return This object.
255       */
256      public Builder validating() {
257         return validating(true);
258      }
259
260      /**
261       * Same as {@link #validating()} but allows you to explicitly specify the value.
262       *
263       * @param value The value for this setting.
264       * @return This object.
265       */
266      public Builder validating(boolean value) {
267         validating = value;
268         return this;
269      }
270      @Override /* Overridden from Builder */
271      public Builder annotations(Annotation...values) {
272         super.annotations(values);
273         return this;
274      }
275
276      @Override /* Overridden from Builder */
277      public Builder apply(AnnotationWorkList work) {
278         super.apply(work);
279         return this;
280      }
281
282      @Override /* Overridden from Builder */
283      public Builder applyAnnotations(Object...from) {
284         super.applyAnnotations(from);
285         return this;
286      }
287
288      @Override /* Overridden from Builder */
289      public Builder applyAnnotations(Class<?>...from) {
290         super.applyAnnotations(from);
291         return this;
292      }
293
294      @Override /* Overridden from Builder */
295      public Builder cache(Cache<HashKey,? extends org.apache.juneau.Context> value) {
296         super.cache(value);
297         return this;
298      }
299
300      @Override /* Overridden from Builder */
301      public Builder debug() {
302         super.debug();
303         return this;
304      }
305
306      @Override /* Overridden from Builder */
307      public Builder debug(boolean value) {
308         super.debug(value);
309         return this;
310      }
311
312      @Override /* Overridden from Builder */
313      public Builder impl(Context value) {
314         super.impl(value);
315         return this;
316      }
317
318      @Override /* Overridden from Builder */
319      public Builder type(Class<? extends org.apache.juneau.Context> value) {
320         super.type(value);
321         return this;
322      }
323
324      @Override /* Overridden from Builder */
325      public Builder beanClassVisibility(Visibility value) {
326         super.beanClassVisibility(value);
327         return this;
328      }
329
330      @Override /* Overridden from Builder */
331      public Builder beanConstructorVisibility(Visibility value) {
332         super.beanConstructorVisibility(value);
333         return this;
334      }
335
336      @Override /* Overridden from Builder */
337      public Builder beanContext(BeanContext value) {
338         super.beanContext(value);
339         return this;
340      }
341
342      @Override /* Overridden from Builder */
343      public Builder beanContext(BeanContext.Builder value) {
344         super.beanContext(value);
345         return this;
346      }
347
348      @Override /* Overridden from Builder */
349      public Builder beanDictionary(java.lang.Class<?>...values) {
350         super.beanDictionary(values);
351         return this;
352      }
353
354      @Override /* Overridden from Builder */
355      public Builder beanFieldVisibility(Visibility value) {
356         super.beanFieldVisibility(value);
357         return this;
358      }
359
360      @Override /* Overridden from Builder */
361      public Builder beanInterceptor(Class<?> on, Class<? extends org.apache.juneau.swap.BeanInterceptor<?>> value) {
362         super.beanInterceptor(on, value);
363         return this;
364      }
365
366      @Override /* Overridden from Builder */
367      public Builder beanMapPutReturnsOldValue() {
368         super.beanMapPutReturnsOldValue();
369         return this;
370      }
371
372      @Override /* Overridden from Builder */
373      public Builder beanMethodVisibility(Visibility value) {
374         super.beanMethodVisibility(value);
375         return this;
376      }
377
378      @Override /* Overridden from Builder */
379      public Builder beanProperties(Map<String,Object> values) {
380         super.beanProperties(values);
381         return this;
382      }
383
384      @Override /* Overridden from Builder */
385      public Builder beanProperties(Class<?> beanClass, String properties) {
386         super.beanProperties(beanClass, properties);
387         return this;
388      }
389
390      @Override /* Overridden from Builder */
391      public Builder beanProperties(String beanClassName, String properties) {
392         super.beanProperties(beanClassName, properties);
393         return this;
394      }
395
396      @Override /* Overridden from Builder */
397      public Builder beanPropertiesExcludes(Map<String,Object> values) {
398         super.beanPropertiesExcludes(values);
399         return this;
400      }
401
402      @Override /* Overridden from Builder */
403      public Builder beanPropertiesExcludes(Class<?> beanClass, String properties) {
404         super.beanPropertiesExcludes(beanClass, properties);
405         return this;
406      }
407
408      @Override /* Overridden from Builder */
409      public Builder beanPropertiesExcludes(String beanClassName, String properties) {
410         super.beanPropertiesExcludes(beanClassName, properties);
411         return this;
412      }
413
414      @Override /* Overridden from Builder */
415      public Builder beanPropertiesReadOnly(Map<String,Object> values) {
416         super.beanPropertiesReadOnly(values);
417         return this;
418      }
419
420      @Override /* Overridden from Builder */
421      public Builder beanPropertiesReadOnly(Class<?> beanClass, String properties) {
422         super.beanPropertiesReadOnly(beanClass, properties);
423         return this;
424      }
425
426      @Override /* Overridden from Builder */
427      public Builder beanPropertiesReadOnly(String beanClassName, String properties) {
428         super.beanPropertiesReadOnly(beanClassName, properties);
429         return this;
430      }
431
432      @Override /* Overridden from Builder */
433      public Builder beanPropertiesWriteOnly(Map<String,Object> values) {
434         super.beanPropertiesWriteOnly(values);
435         return this;
436      }
437
438      @Override /* Overridden from Builder */
439      public Builder beanPropertiesWriteOnly(Class<?> beanClass, String properties) {
440         super.beanPropertiesWriteOnly(beanClass, properties);
441         return this;
442      }
443
444      @Override /* Overridden from Builder */
445      public Builder beanPropertiesWriteOnly(String beanClassName, String properties) {
446         super.beanPropertiesWriteOnly(beanClassName, properties);
447         return this;
448      }
449
450      @Override /* Overridden from Builder */
451      public Builder beansRequireDefaultConstructor() {
452         super.beansRequireDefaultConstructor();
453         return this;
454      }
455
456      @Override /* Overridden from Builder */
457      public Builder beansRequireSerializable() {
458         super.beansRequireSerializable();
459         return this;
460      }
461
462      @Override /* Overridden from Builder */
463      public Builder beansRequireSettersForGetters() {
464         super.beansRequireSettersForGetters();
465         return this;
466      }
467
468      @Override /* Overridden from Builder */
469      public Builder dictionaryOn(Class<?> on, java.lang.Class<?>...values) {
470         super.dictionaryOn(on, values);
471         return this;
472      }
473
474      @Override /* Overridden from Builder */
475      public Builder disableBeansRequireSomeProperties() {
476         super.disableBeansRequireSomeProperties();
477         return this;
478      }
479
480      @Override /* Overridden from Builder */
481      public Builder disableIgnoreMissingSetters() {
482         super.disableIgnoreMissingSetters();
483         return this;
484      }
485
486      @Override /* Overridden from Builder */
487      public Builder disableIgnoreTransientFields() {
488         super.disableIgnoreTransientFields();
489         return this;
490      }
491
492      @Override /* Overridden from Builder */
493      public Builder disableIgnoreUnknownNullBeanProperties() {
494         super.disableIgnoreUnknownNullBeanProperties();
495         return this;
496      }
497
498      @Override /* Overridden from Builder */
499      public Builder disableInterfaceProxies() {
500         super.disableInterfaceProxies();
501         return this;
502      }
503
504      @Override /* Overridden from Builder */
505      public <T> Builder example(Class<T> pojoClass, T o) {
506         super.example(pojoClass, o);
507         return this;
508      }
509
510      @Override /* Overridden from Builder */
511      public <T> Builder example(Class<T> pojoClass, String json) {
512         super.example(pojoClass, json);
513         return this;
514      }
515
516      @Override /* Overridden from Builder */
517      public Builder findFluentSetters() {
518         super.findFluentSetters();
519         return this;
520      }
521
522      @Override /* Overridden from Builder */
523      public Builder findFluentSetters(Class<?> on) {
524         super.findFluentSetters(on);
525         return this;
526      }
527
528      @Override /* Overridden from Builder */
529      public Builder ignoreInvocationExceptionsOnGetters() {
530         super.ignoreInvocationExceptionsOnGetters();
531         return this;
532      }
533
534      @Override /* Overridden from Builder */
535      public Builder ignoreInvocationExceptionsOnSetters() {
536         super.ignoreInvocationExceptionsOnSetters();
537         return this;
538      }
539
540      @Override /* Overridden from Builder */
541      public Builder ignoreUnknownBeanProperties() {
542         super.ignoreUnknownBeanProperties();
543         return this;
544      }
545
546      @Override /* Overridden from Builder */
547      public Builder ignoreUnknownEnumValues() {
548         super.ignoreUnknownEnumValues();
549         return this;
550      }
551
552      @Override /* Overridden from Builder */
553      public Builder implClass(Class<?> interfaceClass, Class<?> implClass) {
554         super.implClass(interfaceClass, implClass);
555         return this;
556      }
557
558      @Override /* Overridden from Builder */
559      public Builder implClasses(Map<Class<?>,Class<?>> values) {
560         super.implClasses(values);
561         return this;
562      }
563
564      @Override /* Overridden from Builder */
565      public Builder interfaceClass(Class<?> on, Class<?> value) {
566         super.interfaceClass(on, value);
567         return this;
568      }
569
570      @Override /* Overridden from Builder */
571      public Builder interfaces(java.lang.Class<?>...value) {
572         super.interfaces(value);
573         return this;
574      }
575
576      @Override /* Overridden from Builder */
577      public Builder locale(Locale value) {
578         super.locale(value);
579         return this;
580      }
581
582      @Override /* Overridden from Builder */
583      public Builder mediaType(MediaType value) {
584         super.mediaType(value);
585         return this;
586      }
587
588      @Override /* Overridden from Builder */
589      public Builder notBeanClasses(java.lang.Class<?>...values) {
590         super.notBeanClasses(values);
591         return this;
592      }
593
594      @Override /* Overridden from Builder */
595      public Builder notBeanPackages(String...values) {
596         super.notBeanPackages(values);
597         return this;
598      }
599
600      @Override /* Overridden from Builder */
601      public Builder propertyNamer(Class<? extends org.apache.juneau.PropertyNamer> value) {
602         super.propertyNamer(value);
603         return this;
604      }
605
606      @Override /* Overridden from Builder */
607      public Builder propertyNamer(Class<?> on, Class<? extends org.apache.juneau.PropertyNamer> value) {
608         super.propertyNamer(on, value);
609         return this;
610      }
611
612      @Override /* Overridden from Builder */
613      public Builder sortProperties() {
614         super.sortProperties();
615         return this;
616      }
617
618      @Override /* Overridden from Builder */
619      public Builder sortProperties(java.lang.Class<?>...on) {
620         super.sortProperties(on);
621         return this;
622      }
623
624      @Override /* Overridden from Builder */
625      public Builder stopClass(Class<?> on, Class<?> value) {
626         super.stopClass(on, value);
627         return this;
628      }
629
630      @Override /* Overridden from Builder */
631      public <T, S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction) {
632         super.swap(normalClass, swappedClass, swapFunction);
633         return this;
634      }
635
636      @Override /* Overridden from Builder */
637      public <T, S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction, ThrowingFunction<S,T> unswapFunction) {
638         super.swap(normalClass, swappedClass, swapFunction, unswapFunction);
639         return this;
640      }
641
642      @Override /* Overridden from Builder */
643      public Builder swaps(Object...values) {
644         super.swaps(values);
645         return this;
646      }
647
648      @Override /* Overridden from Builder */
649      public Builder swaps(Class<?>...values) {
650         super.swaps(values);
651         return this;
652      }
653
654      @Override /* Overridden from Builder */
655      public Builder timeZone(TimeZone value) {
656         super.timeZone(value);
657         return this;
658      }
659
660      @Override /* Overridden from Builder */
661      public Builder typeName(Class<?> on, String value) {
662         super.typeName(on, value);
663         return this;
664      }
665
666      @Override /* Overridden from Builder */
667      public Builder typePropertyName(String value) {
668         super.typePropertyName(value);
669         return this;
670      }
671
672      @Override /* Overridden from Builder */
673      public Builder typePropertyName(Class<?> on, String value) {
674         super.typePropertyName(on, value);
675         return this;
676      }
677
678      @Override /* Overridden from Builder */
679      public Builder useEnumNames() {
680         super.useEnumNames();
681         return this;
682      }
683
684      @Override /* Overridden from Builder */
685      public Builder useJavaBeanIntrospector() {
686         super.useJavaBeanIntrospector();
687         return this;
688      }
689
690      @Override /* Overridden from Builder */
691      public Builder autoCloseStreams() {
692         super.autoCloseStreams();
693         return this;
694      }
695
696      @Override /* Overridden from Builder */
697      public Builder autoCloseStreams(boolean value) {
698         super.autoCloseStreams(value);
699         return this;
700      }
701
702      @Override /* Overridden from Builder */
703      public Builder consumes(String value) {
704         super.consumes(value);
705         return this;
706      }
707
708      @Override /* Overridden from Builder */
709      public Builder debugOutputLines(int value) {
710         super.debugOutputLines(value);
711         return this;
712      }
713
714      @Override /* Overridden from Builder */
715      public Builder listener(Class<? extends org.apache.juneau.parser.ParserListener> value) {
716         super.listener(value);
717         return this;
718      }
719
720      @Override /* Overridden from Builder */
721      public Builder strict() {
722         super.strict();
723         return this;
724      }
725
726      @Override /* Overridden from Builder */
727      public Builder strict(boolean value) {
728         super.strict(value);
729         return this;
730      }
731
732      @Override /* Overridden from Builder */
733      public Builder trimStrings() {
734         super.trimStrings();
735         return this;
736      }
737
738      @Override /* Overridden from Builder */
739      public Builder trimStrings(boolean value) {
740         super.trimStrings(value);
741         return this;
742      }
743
744      @Override /* Overridden from Builder */
745      public Builder unbuffered() {
746         super.unbuffered();
747         return this;
748      }
749
750      @Override /* Overridden from Builder */
751      public Builder unbuffered(boolean value) {
752         super.unbuffered(value);
753         return this;
754      }
755
756      @Override /* Overridden from Builder */
757      public Builder fileCharset(Charset value) {
758         super.fileCharset(value);
759         return this;
760      }
761
762      @Override /* Overridden from Builder */
763      public Builder streamCharset(Charset value) {
764         super.streamCharset(value);
765         return this;
766      }
767   }
768
769   //-------------------------------------------------------------------------------------------------------------------
770   // Instance
771   //-------------------------------------------------------------------------------------------------------------------
772
773   final boolean
774      validating,
775      preserveRootElement;
776   final Class<? extends XMLEventAllocator> eventAllocator;
777   final Class<? extends XMLReporter> reporter;
778   final Class<? extends XMLResolver> resolver;
779
780   private final XMLReporter reporterImpl;
781   private final XMLResolver resolverImpl;
782   private final XMLEventAllocator eventAllocatorImpl;
783   private final Map<ClassMeta<?>,XmlClassMeta> xmlClassMetas = new ConcurrentHashMap<>();
784   private final Map<BeanMeta<?>,XmlBeanMeta> xmlBeanMetas = new ConcurrentHashMap<>();
785   private final Map<BeanPropertyMeta,XmlBeanPropertyMeta> xmlBeanPropertyMetas = new ConcurrentHashMap<>();
786
787   /**
788    * Constructor.
789    *
790    * @param builder
791    *    The property store containing all the settings for this object.
792    */
793   public XmlParser(Builder builder) {
794      super(builder);
795      validating = builder.validating;
796      preserveRootElement = builder.preserveRootElement;
797      reporter = builder.reporter;
798      resolver = builder.resolver;
799      eventAllocator = builder.eventAllocator;
800
801      reporterImpl = reporter != null ? newInstance(reporter) : null;
802      resolverImpl = resolver != null ? newInstance(resolver) : null;
803      eventAllocatorImpl = eventAllocator != null ? newInstance(eventAllocator) : null;
804   }
805
806   @Override /* Context */
807   public Builder copy() {
808      return new Builder(this);
809   }
810
811   @Override /* Context */
812   public XmlParserSession.Builder createSession() {
813      return XmlParserSession.create(this);
814   }
815
816   @Override /* Context */
817   public XmlParserSession getSession() {
818      return createSession().build();
819   }
820
821   //-----------------------------------------------------------------------------------------------------------------
822   // Extended metadata
823   //-----------------------------------------------------------------------------------------------------------------
824
825   @Override /* XmlMetaProvider */
826   public XmlClassMeta getXmlClassMeta(ClassMeta<?> cm) {
827      XmlClassMeta m = xmlClassMetas.get(cm);
828      if (m == null) {
829         m = new XmlClassMeta(cm, this);
830         xmlClassMetas.put(cm, m);
831      }
832      return m;
833   }
834
835   @Override /* XmlMetaProvider */
836   public XmlBeanMeta getXmlBeanMeta(BeanMeta<?> bm) {
837      XmlBeanMeta m = xmlBeanMetas.get(bm);
838      if (m == null) {
839         m = new XmlBeanMeta(bm, this);
840         xmlBeanMetas.put(bm, m);
841      }
842      return m;
843   }
844
845   @Override /* XmlMetaProvider */
846   public XmlBeanPropertyMeta getXmlBeanPropertyMeta(BeanPropertyMeta bpm) {
847      XmlBeanPropertyMeta m = xmlBeanPropertyMetas.get(bpm);
848      if (m == null) {
849         BeanPropertyMeta dbpm = bpm.getDelegateFor();
850         m = new XmlBeanPropertyMeta(dbpm, this);
851         xmlBeanPropertyMetas.put(bpm, m);
852      }
853      return m;
854   }
855
856   //-----------------------------------------------------------------------------------------------------------------
857   // Properties
858   //-----------------------------------------------------------------------------------------------------------------
859
860   /**
861    * XML event allocator.
862    *
863    * @see Builder#eventAllocator(Class)
864    * @return
865    *    The {@link XMLEventAllocator} associated with this parser, or <jk>null</jk> if there isn't one.
866    */
867   protected final XMLEventAllocator getEventAllocator() {
868      return eventAllocatorImpl;
869   }
870
871   /**
872    * Preserve root element during generalized parsing.
873    *
874    * @see Builder#preserveRootElement()
875    * @return
876    *    <jk>true</jk> if when parsing into a generic {@link JsonMap}, the map will contain a single entry whose key
877    *    is the root element name.
878    */
879   protected final boolean isPreserveRootElement() {
880      return preserveRootElement;
881   }
882
883   /**
884    * XML reporter.
885    *
886    * @see Builder#reporter(Class)
887    * @return
888    *    The {@link XMLReporter} associated with this parser, or <jk>null</jk> if there isn't one.
889    */
890   protected final XMLReporter getReporter() {
891      return reporterImpl;
892   }
893
894   /**
895    * XML resolver.
896    *
897    * @see Builder#resolver(Class)
898    * @return
899    *    The {@link XMLResolver} associated with this parser, or <jk>null</jk> if there isn't one.
900    */
901   protected final XMLResolver getResolver() {
902      return resolverImpl;
903   }
904
905   /**
906    * Enable validation.
907    *
908    * @see Builder#validating()
909    * @return
910    *    <jk>true</jk> if XML document will be validated.
911    */
912   protected final boolean isValidating() {
913      return validating;
914   }
915
916   //-----------------------------------------------------------------------------------------------------------------
917   // Other methods
918   //-----------------------------------------------------------------------------------------------------------------
919
920   private <T> T newInstance(Class<T> c) {
921      try {
922         return c.getDeclaredConstructor().newInstance();
923      } catch (Exception e) {
924         throw asRuntimeException(e);
925      }
926   }
927
928   @Override /* Context */
929   protected JsonMap properties() {
930      return filteredMap()
931         .append("validating", validating)
932         .append("preserveRootElement", preserveRootElement)
933         .append("reporter", reporter)
934         .append("resolver", resolver)
935         .append("eventAllocator", eventAllocator);
936   }
937}