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