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