001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.xml;
014
015import org.apache.juneau.*;
016import org.apache.juneau.annotation.*;
017import org.apache.juneau.json.*;
018import org.apache.juneau.serializer.*;
019import org.apache.juneau.xmlschema.XmlSchemaSerializer;
020
021/**
022 * Serializes POJO models to XML.
023 *
024 * <h5 class='topic'>Media types</h5>
025 *
026 * Handles <c>Accept</c> types:  <bc>text/xml</bc>
027 * <p>
028 * Produces <c>Content-Type</c> types:  <bc>text/xml</bc>
029 *
030 * <h5 class='topic'>Description</h5>
031 *
032 * See the {@link JsonSerializer} class for details on how Java models map to JSON.
033 *
034 * <p>
035 * For example, the following JSON...
036 * <p class='bcode w800'>
037 *    {
038 *       name:<js>'John Smith'</js>,
039 *       address: {
040 *          streetAddress: <js>'21 2nd Street'</js>,
041 *          city: <js>'New York'</js>,
042 *          state: <js>'NY'</js>,
043 *          postalCode: <js>10021</js>
044 *       },
045 *       phoneNumbers: [
046 *          <js>'212 555-1111'</js>,
047 *          <js>'212 555-2222'</js>
048 *       ],
049 *       additionalInfo: <jk>null</jk>,
050 *       remote: <jk>false</jk>,
051 *       height: <js>62.4</js>,
052 *       <js>'fico score'</js>:  <js>' &gt; 640'</js>
053 *    }
054 * <p>
055 *    ...maps to the following XML using the default serializer...
056 * <p class='bcode w800'>
057 *    <xt>&lt;object&gt;</xt>
058 *       <xt>&lt;name&gt;</xt>John Smith<xt>&lt;/name&gt;</xt>
059 *       <xt>&lt;address&gt;</xt>
060 *          <xt>&lt;streetAddress&gt;</xt>21 2nd Street<xt>&lt;/streetAddress&gt;</xt>
061 *          <xt>&lt;city&gt;</xt>New York<xt>&lt;/city&gt;</xt>
062 *          <xt>&lt;state&gt;</xt>NY<xt>&lt;/state&gt;</xt>
063 *          <xt>&lt;postalCode&gt;</xt>10021<xt>&lt;/postalCode&gt;</xt>
064 *       <xt>&lt;/address&gt;</xt>
065 *       <xt>&lt;phoneNumbers&gt;</xt>
066 *          <xt>&lt;string&gt;</xt>212 555-1111<xt>&lt;/string&gt;</xt>
067 *          <xt>&lt;string&gt;</xt>212 555-2222<xt>&lt;/string&gt;</xt>
068 *       <xt>&lt;/phoneNumbers&gt;</xt>
069 *       <xt>&lt;additionalInfo</xt> <xa>_type</xa>=<xs>'null'</xs><xt>&gt;&lt;/additionalInfo&gt;</xt>
070 *       <xt>&lt;remote&gt;</xt>false<xt>&lt;/remote&gt;</xt>
071 *       <xt>&lt;height&gt;</xt>62.4<xt>&lt;/height&gt;</xt>
072 *       <xt>&lt;fico_x0020_score&gt;</xt> &amp;gt; 640<xt>&lt;/fico_x0020_score&gt;</xt>
073 *    <xt>&lt;/object&gt;</xt>
074 *
075 * <p>
076 * An additional "add-json-properties" mode is also provided to prevent loss of JSON data types...
077 * <p class='bcode w800'>
078 *       <xt>&lt;name</xt> <xa>_type</xa>=<xs>'string'</xs><xt>&gt;</xt>John Smith<xt>&lt;/name&gt;</xt>
079 *       <xt>&lt;address</xt> <xa>_type</xa>=<xs>'object'</xs><xt>&gt;</xt>
080 *          <xt>&lt;streetAddress</xt> <xa>_type</xa>=<xs>'string'</xs><xt>&gt;</xt>21 2nd Street<xt>&lt;/streetAddress&gt;</xt>
081 *          <xt>&lt;city</xt> <xa>_type</xa>=<xs>'string'</xs><xt>&gt;</xt>New York<xt>&lt;/city&gt;</xt>
082 *          <xt>&lt;state</xt> <xa>_type</xa>=<xs>'string'</xs><xt>&gt;</xt>NY<xt>&lt;/state&gt;</xt>
083 *          <xt>&lt;postalCode</xt> <xa>_type</xa>=<xs>'number'</xs><xt>&gt;</xt>10021<xt>&lt;/postalCode&gt;</xt>
084 *       <xt>&lt;/address&gt;</xt>
085 *       <xt>&lt;phoneNumbers</xt> <xa>_type</xa>=<xs>'array'</xs><xt>&gt;</xt>
086 *          <xt>&lt;string&gt;</xt>212 555-1111<xt>&lt;/string&gt;</xt>
087 *          <xt>&lt;string&gt;</xt>212 555-2222<xt>&lt;/string&gt;</xt>
088 *       <xt>&lt;/phoneNumbers&gt;</xt>
089 *       <xt>&lt;additionalInfo</xt> <xa>_type</xa>=<xs>'null'</xs><xt>&gt;&lt;/additionalInfo&gt;</xt>
090 *       <xt>&lt;remote</xt> <xa>_type</xa>=<xs>'boolean'</xs><xt>&gt;</xt>false<xt>&lt;/remote&gt;</xt>
091 *       <xt>&lt;height</xt> <xa>_type</xa>=<xs>'number'</xs><xt>&gt;</xt>62.4<xt>&lt;/height&gt;</xt>
092 *       <xt>&lt;fico_x0020_score</xt> <xa>_type</xa>=<xs>'string'</xs><xt>&gt;</xt> &amp;gt; 640<xt>&lt;/fico_x0020_score&gt;</xt>
093 *    <xt>&lt;/object&gt;</xt>
094 * </p>
095 *
096 * <p>
097 * This serializer provides several serialization options.
098 * Typically, one of the predefined <jsf>DEFAULT</jsf> serializers will be sufficient.
099 * However, custom serializers can be constructed to fine-tune behavior.
100 *
101 * <p>
102 * If an attribute name contains any non-valid XML element characters, they will be escaped using standard
103 * {@code _x####_} notation.
104 *
105 * <h5 class='topic'>Behavior-specific subclasses</h5>
106 *
107 * The following direct subclasses are provided for convenience:
108 * <ul>
109 *    <li>{@link Sq} - Default serializer, single quotes.
110 *    <li>{@link SqReadable} - Default serializer, single quotes, whitespace added.
111 * </ul>
112 */
113@ConfigurableContext
114public class XmlSerializer extends WriterSerializer {
115
116   //-------------------------------------------------------------------------------------------------------------------
117   // Configurable properties
118   //-------------------------------------------------------------------------------------------------------------------
119
120   static final String PREFIX = "XmlSerializer";
121
122   /**
123    * Configuration property:  Add <js>"_type"</js> properties when needed.
124    *
125    * <h5 class='section'>Property:</h5>
126    * <ul>
127    *    <li><b>Name:</b>  <js>"XmlSerializer.addBeanTypes.b"</js>
128    *    <li><b>Data type:</b>  <c>Boolean</c>
129    *    <li><b>Default:</b>  <jk>false</jk>
130    *    <li><b>Session property:</b>  <jk>false</jk>
131    *    <li><b>Methods:</b>
132    *       <ul>
133    *          <li class='jm'>{@link XmlSerializerBuilder#addBeanTypes(boolean)}
134    *       </ul>
135    * </ul>
136    *
137    * <h5 class='section'>Description:</h5>
138    * <p>
139    * If <jk>true</jk>, then <js>"_type"</js> properties will be added to beans if their type cannot be inferred
140    * through reflection.
141    *
142    * <p>
143    * When present, this value overrides the {@link #SERIALIZER_addBeanTypes} setting and is
144    * provided to customize the behavior of specific serializers in a {@link SerializerGroup}.
145    */
146   public static final String XML_addBeanTypes = PREFIX + ".addBeanTypes.b";
147
148   /**
149    * Configuration property:  Add namespace URLs to the root element.
150    *
151    * <h5 class='section'>Property:</h5>
152    * <ul>
153    *    <li><b>Name:</b>  <js>"XmlSerializer.addNamespaceUrisToRoot.b"</js>
154    *    <li><b>Data type:</b>  <c>Boolean</c>
155    *    <li><b>Default:</b>  <jk>false</jk>
156    *    <li><b>Session property:</b>  <jk>false</jk>
157    *    <li><b>Methods:</b>
158    *       <ul>
159    *          <li class='jm'>{@link XmlSerializerBuilder#addNamespaceUrisToRoot(boolean)}
160    *          <li class='jm'>{@link XmlSerializerBuilder#addNamespaceUrisToRoot()}
161    *       </ul>
162    * </ul>
163    *
164    * <h5 class='section'>Description:</h5>
165    * <p>
166    * Use this setting to add {@code xmlns:x} attributes to the root element for the default and all mapped namespaces.
167    *
168    * <p>
169    * This setting is ignored if {@link #XML_enableNamespaces} is not enabled.
170    *
171    * <ul class='seealso'>
172    *    <li class='link'>{@doc juneau-marshall.XmlDetails.Namespaces}
173    * </ul>
174    */
175   public static final String XML_addNamespaceUrisToRoot = PREFIX + ".addNamespaceUrisToRoot.b";
176
177   /**
178    * Configuration property:  Auto-detect namespace usage.
179    *
180    * <h5 class='section'>Property:</h5>
181    * <ul>
182    *    <li><b>Name:</b>  <js>"XmlSerializer.autoDetectNamespaces.b"</js>
183    *    <li><b>Data type:</b>  <c>Boolean</c>
184    *    <li><b>Default:</b>  <jk>true</jk>
185    *    <li><b>Session property:</b>  <jk>false</jk>
186    *    <li><b>Methods:</b>
187    *       <ul>
188    *          <li class='jm'>{@link XmlSerializerBuilder#autoDetectNamespaces(boolean)}
189    *       </ul>
190    * </ul>
191    *
192    * <h5 class='section'>Description:</h5>
193    * <p>
194    * Detect namespace usage before serialization.
195    *
196    * <p>
197    * Used in conjunction with {@link #XML_addNamespaceUrisToRoot} to reduce the list of namespace URLs appended to the
198    * root element to only those that will be used in the resulting document.
199    *
200    * <p>
201    * If enabled, then the data structure will first be crawled looking for namespaces that will be encountered before
202    * the root element is serialized.
203    *
204    * <p>
205    * This setting is ignored if {@link #XML_enableNamespaces} is not enabled.
206    *
207    * <ul class='notes'>
208    *    <li>
209    *       Auto-detection of namespaces can be costly performance-wise.
210    *       <br>In high-performance environments, it's recommended that namespace detection be
211    *       disabled, and that namespaces be manually defined through the {@link #XML_namespaces} property.
212    * </ul>
213    *
214    * <ul class='seealso'>
215    *    <li class='link'>{@doc juneau-marshall.XmlDetails.Namespaces}
216    * </ul>
217    */
218   public static final String XML_autoDetectNamespaces = PREFIX + ".autoDetectNamespaces.b";
219
220   /**
221    * Configuration property:  Default namespace.
222    *
223    * <h5 class='section'>Property:</h5>
224    * <ul>
225    *    <li><b>Name:</b>  <js>"XmlSerializer.defaultNamespace.s"</js>
226    *    <li><b>Data type:</b>  <c>String</c> ({@link Namespace})
227    *    <li><b>Default:</b>  <js>"juneau: http://www.apache.org/2013/Juneau"</js>
228    *    <li><b>Session property:</b>  <jk>false</jk>
229    *    <li><b>Methods:</b>
230    *       <ul>
231    *          <li class='jm'>{@link XmlSerializerBuilder#defaultNamespace(String)}
232    *       </ul>
233    * </ul>
234    *
235    * <h5 class='section'>Description:</h5>
236    * <p>
237    * Specifies the default namespace URI for this document.
238    *
239    * <ul class='seealso'>
240    *    <li class='link'>{@doc juneau-marshall.XmlDetails.Namespaces}
241    * </ul>
242    */
243   public static final String XML_defaultNamespace = PREFIX + ".defaultNamespace.s";
244
245   /**
246    * Configuration property:  Enable support for XML namespaces.
247    *
248    * <h5 class='section'>Property:</h5>
249    * <ul>
250    *    <li><b>Name:</b>  <js>"XmlSerializer.enableNamespaces.b"</js>
251    *    <li><b>Data type:</b>  <c>Boolean</c>
252    *    <li><b>Default:</b>  <jk>false</jk>
253    *    <li><b>Session property:</b>  <jk>false</jk>
254    *    <li><b>Methods:</b>
255    *       <ul>
256    *          <li class='jm'>{@link XmlSerializerBuilder#enableNamespaces(boolean)}
257    *       </ul>
258    * </ul>
259    *
260    * <h5 class='section'>Description:</h5>
261    * <p>
262    * If not enabled, XML output will not contain any namespaces regardless of any other settings.
263    *
264    * <ul class='seealso'>
265    *    <li class='link'>{@doc juneau-marshall.XmlDetails.Namespaces}
266    * </ul>
267    */
268   public static final String XML_enableNamespaces = PREFIX + ".enableNamespaces.b";
269
270   /**
271    * Configuration property:  Default namespaces.
272    *
273    * <h5 class='section'>Property:</h5>
274    * <ul>
275    *    <li><b>Name:</b>  <js>"XmlSerializer.namespaces.ls"</js>
276    *    <li><b>Data type:</b>  <c>Set&lt;String&gt;</c> ({@link Namespace})
277    *    <li><b>Default:</b>  empty set
278    *    <li><b>Session property:</b>  <jk>false</jk>
279    *    <li><b>Methods:</b>
280    *       <ul>
281    *          <li class='jm'>{@link XmlSerializerBuilder#defaultNamespace(String)}
282    *       </ul>
283    * </ul>
284    *
285    * <h5 class='section'>Description:</h5>
286    * <p>
287    * The default list of namespaces associated with this serializer.
288    *
289    * <ul class='seealso'>
290    *    <li class='link'>{@doc juneau-marshall.XmlDetails.Namespaces}
291    * </ul>
292    */
293   public static final String XML_namespaces = PREFIX + ".namespaces.ls";
294
295   /**
296    * Configuration property:  XMLSchema namespace.
297    *
298    * <h5 class='section'>Property:</h5>
299    * <ul>
300    *    <li><b>Name:</b>  <js>"XmlSerializer.xsNamespace.s"</js>
301    *    <li><b>Data type:</b>  <c>String</c> ({@link Namespace})
302    *    <li><b>Default:</b>  <js>"xs: http://www.w3.org/2001/XMLSchema"</js>
303    *    <li><b>Session property:</b>  <jk>false</jk>
304    *    <li><b>Methods:</b>
305    *       <ul>
306    *          <li class='jm'>{@link XmlSerializerBuilder#xsNamespace(Namespace)}
307    *       </ul>
308    * </ul>
309    *
310    * <h5 class='section'>Description:</h5>
311    * <p>
312    * Specifies the namespace for the <c>XMLSchema</c> namespace, used by the schema generated by the
313    * {@link XmlSchemaSerializer} class.
314    *
315    * <ul class='seealso'>
316    *    <li class='link'>{@doc juneau-marshall.XmlDetails.Namespaces}
317    * </ul>
318    */
319   public static final String XML_xsNamespace = PREFIX + ".xsNamespace.s";
320
321
322   //-------------------------------------------------------------------------------------------------------------------
323   // Predefined instances
324   //-------------------------------------------------------------------------------------------------------------------
325
326   /** Default serializer without namespaces. */
327   public static final XmlSerializer DEFAULT = new XmlSerializer(PropertyStore.DEFAULT);
328
329   /** Default serializer without namespaces, with single quotes. */
330   public static final XmlSerializer DEFAULT_SQ = new Sq(PropertyStore.DEFAULT);
331
332   /** Default serializer without namespaces, with single quotes, whitespace added. */
333   public static final XmlSerializer DEFAULT_SQ_READABLE = new SqReadable(PropertyStore.DEFAULT);
334
335   /** Default serializer, all default settings. */
336   public static final XmlSerializer DEFAULT_NS = new Ns(PropertyStore.DEFAULT);
337
338   /** Default serializer, single quotes. */
339   public static final XmlSerializer DEFAULT_NS_SQ = new NsSq(PropertyStore.DEFAULT);
340
341   /** Default serializer, single quotes, whitespace added. */
342   public static final XmlSerializer DEFAULT_NS_SQ_READABLE = new NsSqReadable(PropertyStore.DEFAULT);
343
344
345   //-------------------------------------------------------------------------------------------------------------------
346   // Predefined subclasses
347   //-------------------------------------------------------------------------------------------------------------------
348
349   /** Default serializer, single quotes. */
350   public static class Sq extends XmlSerializer {
351
352      /**
353       * Constructor.
354       *
355       * @param ps The property store containing all the settings for this object.
356       */
357      public Sq(PropertyStore ps) {
358         super(
359            ps.builder()
360               .set(WSERIALIZER_quoteChar, '\'')
361               .build()
362            );
363      }
364   }
365
366   /** Default serializer, single quotes, whitespace added. */
367   public static class SqReadable extends XmlSerializer {
368
369      /**
370       * Constructor.
371       *
372       * @param ps The property store containing all the settings for this object.
373       */
374      public SqReadable(PropertyStore ps) {
375         super(
376            ps.builder()
377               .set(WSERIALIZER_quoteChar, '\'')
378               .set(WSERIALIZER_useWhitespace, true)
379               .build()
380            );
381      }
382   }
383
384   /** Default serializer without namespaces. */
385   public static class Ns extends XmlSerializer {
386
387      /**
388       * Constructor.
389       *
390       * @param ps The property store containing all the settings for this object.
391       */
392      public Ns(PropertyStore ps) {
393         super(
394            ps.builder()
395               .set(XML_enableNamespaces, true)
396               .build(),
397            "text/xml",
398            "text/xml+simple"
399         );
400      }
401   }
402
403   /** Default serializer without namespaces, single quotes. */
404   public static class NsSq extends XmlSerializer {
405
406      /**
407       * Constructor.
408       *
409       * @param ps The property store containing all the settings for this object.
410       */
411      public NsSq(PropertyStore ps) {
412         super(
413            ps.builder()
414               .set(XML_enableNamespaces, true)
415               .set(WSERIALIZER_quoteChar, '\'')
416               .build()
417            );
418      }
419   }
420
421   /** Default serializer without namespaces, single quotes, with whitespace. */
422   public static class NsSqReadable extends XmlSerializer {
423
424      /**
425       * Constructor.
426       *
427       * @param ps The property store containing all the settings for this object.
428       */
429      public NsSqReadable(PropertyStore ps) {
430         super(
431            ps.builder()
432               .set(XML_enableNamespaces, true)
433               .set(WSERIALIZER_quoteChar, '\'')
434               .set(WSERIALIZER_useWhitespace, true)
435               .build()
436            );
437      }
438   }
439
440   @SuppressWarnings("javadoc")
441   protected static final Namespace
442      DEFAULT_JUNEAU_NAMESPACE = Namespace.create("juneau", "http://www.apache.org/2013/Juneau"),
443      DEFAULT_XS_NAMESPACE = Namespace.create("xs", "http://www.w3.org/2001/XMLSchema");
444
445   //-------------------------------------------------------------------------------------------------------------------
446   // Instance
447   //-------------------------------------------------------------------------------------------------------------------
448
449   private final boolean
450      autoDetectNamespaces,
451      enableNamespaces,
452      addNamespaceUrlsToRoot,
453      addBeanTypes;
454   private final Namespace defaultNamespace;
455   private final Namespace
456      xsNamespace;
457   private final Namespace[] namespaces;
458
459   private volatile XmlSchemaSerializer schemaSerializer;
460
461   /**
462    * Constructor.
463    *
464    * @param ps
465    *    The property store containing all the settings for this object.
466    */
467   public XmlSerializer(PropertyStore ps) {
468      this(ps, "text/xml", (String)null);
469   }
470
471   /**
472    * Constructor.
473    *
474    * @param ps
475    *    The property store containing all the settings for this object.
476    * @param produces
477    *    The media type that this serializer produces.
478    * @param accept
479    *    The accept media types that the serializer can handle.
480    *    <p>
481    *    Can contain meta-characters per the <c>media-type</c> specification of {@doc RFC2616.section14.1}
482    *    <p>
483    *    If empty, then assumes the only media type supported is <c>produces</c>.
484    *    <p>
485    *    For example, if this serializer produces <js>"application/json"</js> but should handle media types of
486    *    <js>"application/json"</js> and <js>"text/json"</js>, then the arguments should be:
487    *    <p class='bcode w800'>
488    *    <jk>super</jk>(ps, <js>"application/json"</js>, <js>"application/json,text/json"</js>);
489    *    </p>
490    *    <br>...or...
491    *    <p class='bcode w800'>
492    *    <jk>super</jk>(ps, <js>"application/json"</js>, <js>"*&#8203;/json"</js>);
493    *    </p>
494    * <p>
495    * The accept value can also contain q-values.
496    */
497   public XmlSerializer(PropertyStore ps, String produces, String accept) {
498      super(ps, produces, accept);
499      autoDetectNamespaces = getBooleanProperty(XML_autoDetectNamespaces, true);
500      enableNamespaces = getBooleanProperty(XML_enableNamespaces, false);
501      addNamespaceUrlsToRoot = getBooleanProperty(XML_addNamespaceUrisToRoot, false);
502      defaultNamespace = getInstanceProperty(XML_defaultNamespace, Namespace.class, DEFAULT_JUNEAU_NAMESPACE);
503      addBeanTypes = getBooleanProperty(XML_addBeanTypes, getBooleanProperty(SERIALIZER_addBeanTypes, false));
504      xsNamespace = getInstanceProperty(XML_xsNamespace, Namespace.class, DEFAULT_XS_NAMESPACE);
505      namespaces = getInstanceArrayProperty(XML_namespaces, Namespace.class, new Namespace[0]);
506   }
507
508   @Override /* Context */
509   public XmlSerializerBuilder builder() {
510      return new XmlSerializerBuilder(getPropertyStore());
511   }
512
513   /**
514    * Instantiates a new clean-slate {@link XmlSerializerBuilder} object.
515    *
516    * <p>
517    * This is equivalent to simply calling <code><jk>new</jk> XmlSerializerBuilder()</code>.
518    *
519    * <p>
520    * Note that this method creates a builder initialized to all default settings, whereas {@link #builder()} copies
521    * the settings of the object called on.
522    *
523    * @return A new {@link XmlSerializerBuilder} object.
524    */
525   public static XmlSerializerBuilder create() {
526      return new XmlSerializerBuilder();
527   }
528
529   /**
530    * Returns the schema serializer based on the settings of this serializer.
531    * @return The schema serializer.
532    */
533   public XmlSerializer getSchemaSerializer() {
534      if (schemaSerializer == null)
535         schemaSerializer = builder().build(XmlSchemaSerializer.class);
536      return schemaSerializer;
537   }
538
539   @Override /* Serializer */
540   public XmlSerializerSession createSession() {
541      return createSession(createDefaultSessionArgs());
542   }
543
544   @Override /* Serializer */
545   public XmlSerializerSession createSession(SerializerSessionArgs args) {
546      return new XmlSerializerSession(this, args);
547   }
548
549   //-----------------------------------------------------------------------------------------------------------------
550   // Properties
551   //-----------------------------------------------------------------------------------------------------------------
552
553   /**
554    * Configuration property:  Add <js>"_type"</js> properties when needed.
555    *
556    * @see #XML_addBeanTypes
557    * @return
558    *    <jk>true</jk> if<js>"_type"</js> properties will be added to beans if their type cannot be inferred
559    *    through reflection.
560    */
561   @Override
562   protected boolean isAddBeanTypes() {
563      return addBeanTypes;
564   }
565
566   /**
567    * Configuration property:  Add namespace URLs to the root element.
568    *
569    * @see #XML_addNamespaceUrisToRoot
570    * @return
571    *    <jk>true</jk> if {@code xmlns:x} attributes are added to the root element for the default and all mapped namespaces.
572    */
573   protected final boolean isAddNamespaceUrlsToRoot() {
574      return addNamespaceUrlsToRoot;
575   }
576
577   /**
578    * Configuration property:  Auto-detect namespace usage.
579    *
580    * @see #XML_autoDetectNamespaces
581    * @return
582    *    <jk>true</jk> if namespace usage is detected before serialization.
583    */
584   protected final boolean isAutoDetectNamespaces() {
585      return autoDetectNamespaces;
586   }
587
588   /**
589    * Configuration property:  Default namespace.
590    *
591    * @see #XML_defaultNamespace
592    * @return
593    *    The default namespace URI for this document.
594    */
595   protected final Namespace getDefaultNamespace() {
596      return defaultNamespace;
597   }
598
599   /**
600    * Configuration property:  Enable support for XML namespaces.
601    *
602    * @see #XML_enableNamespaces
603    * @return
604    *    <jk>false</jk> if XML output will not contain any namespaces regardless of any other settings.
605    */
606   protected final boolean isEnableNamespaces() {
607      return enableNamespaces;
608   }
609
610   /**
611    * Configuration property:  Default namespaces.
612    *
613    * @see #XML_namespaces
614    * @return
615    *    The default list of namespaces associated with this serializer.
616    */
617   protected final Namespace[] getNamespaces() {
618      return namespaces;
619   }
620
621   /**
622    * Configuration property:  XMLSchema namespace.
623    *
624    * @see #XML_xsNamespace
625    * @return
626    *    The namespace for the <c>XMLSchema</c> namespace, used by the schema generated by the
627    *    {@link XmlSchemaSerializer} class.
628    */
629   protected final Namespace getXsNamespace() {
630      return xsNamespace;
631   }
632
633   //-----------------------------------------------------------------------------------------------------------------
634   // Other methods
635   //-----------------------------------------------------------------------------------------------------------------
636
637   @Override /* Context */
638   public ObjectMap toMap() {
639      return super.toMap()
640         .append("XmlSerializer", new DefaultFilteringObjectMap()
641            .append("autoDetectNamespaces", autoDetectNamespaces)
642            .append("enableNamespaces", enableNamespaces)
643            .append("addNamespaceUrlsToRoot", addNamespaceUrlsToRoot)
644            .append("defaultNamespace", defaultNamespace)
645            .append("xsNamespace", xsNamespace)
646            .append("namespaces", namespaces)
647            .append("addBeanTypes", addBeanTypes)
648         );
649   }
650}