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.*;
018
019/**
020 * Serializes POJO models to XML.
021 * 
022 * <h5 class='topic'>Media types</h5>
023 * 
024 * Handles <code>Accept</code> types:  <code><b>text/xml</b></code>
025 * <p>
026 * Produces <code>Content-Type</code> types:  <code><b>text/xml</b></code>
027 * 
028 * <h5 class='topic'>Description</h5>
029 * 
030 * See the {@link JsonSerializer} class for details on how Java models map to JSON.
031 * 
032 * <p>
033 * For example, the following JSON...
034 * <p class='bcode'>
035 *    {
036 *       name:<js>'John Smith'</js>,
037 *       address: {
038 *          streetAddress: <js>'21 2nd Street'</js>,
039 *          city: <js>'New York'</js>,
040 *          state: <js>'NY'</js>,
041 *          postalCode: <js>10021</js>
042 *       },
043 *       phoneNumbers: [
044 *          <js>'212 555-1111'</js>,
045 *          <js>'212 555-2222'</js>
046 *       ],
047 *       additionalInfo: <jk>null</jk>,
048 *       remote: <jk>false</jk>,
049 *       height: <js>62.4</js>,
050 *       <js>'fico score'</js>:  <js>' &gt; 640'</js>
051 *    }
052 * <p>
053 *    ...maps to the following XML using the default serializer...
054 * <p class='bcode'>
055 *    <xt>&lt;object&gt;</xt>
056 *       <xt>&lt;name&gt;</xt>John Smith<xt>&lt;/name&gt;</xt>
057 *       <xt>&lt;address&gt;</xt>
058 *          <xt>&lt;streetAddress&gt;</xt>21 2nd Street<xt>&lt;/streetAddress&gt;</xt>
059 *          <xt>&lt;city&gt;</xt>New York<xt>&lt;/city&gt;</xt>
060 *          <xt>&lt;state&gt;</xt>NY<xt>&lt;/state&gt;</xt>
061 *          <xt>&lt;postalCode&gt;</xt>10021<xt>&lt;/postalCode&gt;</xt>
062 *       <xt>&lt;/address&gt;</xt>
063 *       <xt>&lt;phoneNumbers&gt;</xt>
064 *          <xt>&lt;string&gt;</xt>212 555-1111<xt>&lt;/string&gt;</xt>
065 *          <xt>&lt;string&gt;</xt>212 555-2222<xt>&lt;/string&gt;</xt>
066 *       <xt>&lt;/phoneNumbers&gt;</xt>
067 *       <xt>&lt;additionalInfo</xt> <xa>_type</xa>=<xs>'null'</xs><xt>&gt;&lt;/additionalInfo&gt;</xt>
068 *       <xt>&lt;remote&gt;</xt>false<xt>&lt;/remote&gt;</xt>
069 *       <xt>&lt;height&gt;</xt>62.4<xt>&lt;/height&gt;</xt>
070 *       <xt>&lt;fico_x0020_score&gt;</xt> &amp;gt; 640<xt>&lt;/fico_x0020_score&gt;</xt>
071 *    <xt>&lt;/object&gt;</xt>
072 * 
073 * <p>
074 * An additional "add-json-properties" mode is also provided to prevent loss of JSON data types...
075 * <p class='bcode'>
076 *       <xt>&lt;name</xt> <xa>_type</xa>=<xs>'string'</xs><xt>&gt;</xt>John Smith<xt>&lt;/name&gt;</xt>
077 *       <xt>&lt;address</xt> <xa>_type</xa>=<xs>'object'</xs><xt>&gt;</xt>
078 *          <xt>&lt;streetAddress</xt> <xa>_type</xa>=<xs>'string'</xs><xt>&gt;</xt>21 2nd Street<xt>&lt;/streetAddress&gt;</xt>
079 *          <xt>&lt;city</xt> <xa>_type</xa>=<xs>'string'</xs><xt>&gt;</xt>New York<xt>&lt;/city&gt;</xt>
080 *          <xt>&lt;state</xt> <xa>_type</xa>=<xs>'string'</xs><xt>&gt;</xt>NY<xt>&lt;/state&gt;</xt>
081 *          <xt>&lt;postalCode</xt> <xa>_type</xa>=<xs>'number'</xs><xt>&gt;</xt>10021<xt>&lt;/postalCode&gt;</xt>
082 *       <xt>&lt;/address&gt;</xt>
083 *       <xt>&lt;phoneNumbers</xt> <xa>_type</xa>=<xs>'array'</xs><xt>&gt;</xt>
084 *          <xt>&lt;string&gt;</xt>212 555-1111<xt>&lt;/string&gt;</xt>
085 *          <xt>&lt;string&gt;</xt>212 555-2222<xt>&lt;/string&gt;</xt>
086 *       <xt>&lt;/phoneNumbers&gt;</xt>
087 *       <xt>&lt;additionalInfo</xt> <xa>_type</xa>=<xs>'null'</xs><xt>&gt;&lt;/additionalInfo&gt;</xt>
088 *       <xt>&lt;remote</xt> <xa>_type</xa>=<xs>'boolean'</xs><xt>&gt;</xt>false<xt>&lt;/remote&gt;</xt>
089 *       <xt>&lt;height</xt> <xa>_type</xa>=<xs>'number'</xs><xt>&gt;</xt>62.4<xt>&lt;/height&gt;</xt>
090 *       <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>
091 *    <xt>&lt;/object&gt;</xt>
092 * </p>
093 * 
094 * <p>
095 * This serializer provides several serialization options.
096 * Typically, one of the predefined <jsf>DEFAULT</jsf> serializers will be sufficient.
097 * However, custom serializers can be constructed to fine-tune behavior.
098 * 
099 * <p>
100 * If an attribute name contains any non-valid XML element characters, they will be escaped using standard
101 * {@code _x####_} notation.
102 * 
103 * <h5 class='topic'>Behavior-specific subclasses</h5>
104 * 
105 * The following direct subclasses are provided for convenience:
106 * <ul>
107 *    <li>{@link Sq} - Default serializer, single quotes.
108 *    <li>{@link SqReadable} - Default serializer, single quotes, whitespace added.
109 * </ul>
110 */
111public class XmlSerializer extends WriterSerializer {
112
113   //-------------------------------------------------------------------------------------------------------------------
114   // Configurable properties
115   //-------------------------------------------------------------------------------------------------------------------
116
117   private static final String PREFIX = "XmlSerializer.";
118
119   /**
120    * Configuration property:  Add <js>"_type"</js> properties when needed.
121    * 
122    * <h5 class='section'>Property:</h5>
123    * <ul>
124    *    <li><b>Name:</b>  <js>"XmlSerializer.addBeanTypeProperties.b"</js>
125    *    <li><b>Data type:</b>  <code>Boolean</code>
126    *    <li><b>Default:</b>  <jk>false</jk>
127    *    <li><b>Session-overridable:</b>  <jk>true</jk>
128    *    <li><b>Methods:</b> 
129    *       <ul>
130    *          <li class='jm'>{@link XmlSerializerBuilder#addBeanTypeProperties(boolean)}
131    *       </ul>
132    * </ul>
133    * 
134    * <h5 class='section'>Description:</h5>
135    * <p>
136    * If <jk>true</jk>, then <js>"_type"</js> properties will be added to beans if their type cannot be inferred
137    * through reflection.
138    * 
139    * <p>
140    * When present, this value overrides the {@link #SERIALIZER_addBeanTypeProperties} setting and is
141    * provided to customize the behavior of specific serializers in a {@link SerializerGroup}.
142    */
143   public static final String XML_addBeanTypeProperties = PREFIX + "addBeanTypeProperties.b";
144
145   /**
146    * Configuration property:  Add namespace URLs to the root element.
147    * 
148    * <h5 class='section'>Property:</h5>
149    * <ul>
150    *    <li><b>Name:</b>  <js>"XmlSerializer.addNamespaceUrisToRoot.b"</js>
151    *    <li><b>Data type:</b>  <code>Boolean</code>
152    *    <li><b>Default:</b>  <jk>false</jk>
153    *    <li><b>Session-overridable:</b>  <jk>true</jk>
154    *    <li><b>Methods:</b> 
155    *       <ul>
156    *          <li class='jm'>{@link XmlSerializerBuilder#addNamespaceUrisToRoot(boolean)}
157    *          <li class='jm'>{@link XmlSerializerBuilder#addNamespaceUrisToRoot()}
158    *       </ul>
159    * </ul>
160    * 
161    * <h5 class='section'>Description:</h5>
162    * <p>
163    * Use this setting to add {@code xmlns:x} attributes to the root element for the default and all mapped namespaces.
164    * 
165    * <p>
166    * This setting is ignored if {@link #XML_enableNamespaces} is not enabled.
167    * 
168    * <h5 class='section'>See Also:</h5>
169    * <ul>
170    *    <li class='link'><a class="doclink" href="package-summary.html#Namespaces">org.apache.juneau.xml &gt; Namespaces</a>
171    * </ul>
172    */
173   public static final String XML_addNamespaceUrisToRoot = PREFIX + "addNamespaceUrisToRoot.b";
174
175   /**
176    * Configuration property:  Auto-detect namespace usage.
177    * 
178    * <h5 class='section'>Property:</h5>
179    * <ul>
180    *    <li><b>Name:</b>  <js>"XmlSerializer.autoDetectNamespaces.b"</js>
181    *    <li><b>Data type:</b>  <code>Boolean</code>
182    *    <li><b>Default:</b>  <jk>true</jk>
183    *    <li><b>Session-overridable:</b>  <jk>true</jk>
184    *    <li><b>Methods:</b> 
185    *       <ul>
186    *          <li class='jm'>{@link XmlSerializerBuilder#autoDetectNamespaces(boolean)}
187    *       </ul>
188    * </ul>
189    * 
190    * <h5 class='section'>Description:</h5>
191    * <p>
192    * Detect namespace usage before serialization.
193    * 
194    * <p>
195    * Used in conjunction with {@link #XML_addNamespaceUrisToRoot} to reduce the list of namespace URLs appended to the
196    * root element to only those that will be used in the resulting document.
197    * 
198    * <p>
199    * If enabled, then the data structure will first be crawled looking for namespaces that will be encountered before
200    * the root element is serialized.
201    * 
202    * <p>
203    * This setting is ignored if {@link #XML_enableNamespaces} is not enabled.
204    * 
205    * <h5 class='section'>Notes:</h5>
206    * <ul class='spaced-list'>
207    *    <li>
208    *       Auto-detection of namespaces can be costly performance-wise.
209    *       <br>In high-performance environments, it's recommended that namespace detection be
210    *       disabled, and that namespaces be manually defined through the {@link #XML_namespaces} property.
211    * </ul>
212    * 
213    * <h5 class='section'>See Also:</h5>
214    * <ul>
215    *    <li class='link'><a class="doclink" href="package-summary.html#Namespaces">org.apache.juneau.xml &gt; Namespaces</a>
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>  <code>String</code> ({@link Namespace})
227    *    <li><b>Default:</b>  <js>"juneau: http://www.apache.org/2013/Juneau"</js>
228    *    <li><b>Session-overridable:</b>  <jk>true</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    * <h5 class='section'>See Also:</h5>
240    * <ul>
241    *    <li class='link'><a class="doclink" href="package-summary.html#Namespaces">org.apache.juneau.xml &gt; Namespaces</a>
242    * </ul>
243    */
244   public static final String XML_defaultNamespace = PREFIX + "defaultNamespace.s";
245
246   /**
247    * Configuration property:  Enable support for XML namespaces.
248    * 
249    * <h5 class='section'>Property:</h5>
250    * <ul>
251    *    <li><b>Name:</b>  <js>"XmlSerializer.enableNamespaces.b"</js>
252    *    <li><b>Data type:</b>  <code>Boolean</code>
253    *    <li><b>Default:</b>  <jk>false</jk>
254    *    <li><b>Session-overridable:</b>  <jk>true</jk>
255    *    <li><b>Methods:</b> 
256    *       <ul>
257    *          <li class='jm'>{@link XmlSerializerBuilder#enableNamespaces(boolean)}
258    *       </ul>
259    * </ul>
260    * 
261    * <h5 class='section'>Description:</h5>
262    * <p>
263    * If not enabled, XML output will not contain any namespaces regardless of any other settings.
264    * 
265    * <h5 class='section'>See Also:</h5>
266    * <ul>
267    *    <li class='link'><a class="doclink" href="package-summary.html#Namespaces">org.apache.juneau.xml &gt; Namespaces</a>
268    * </ul>
269    */
270   public static final String XML_enableNamespaces = PREFIX + "enableNamespaces.b";
271
272   /**
273    * Configuration property:  Default namespaces.
274    * 
275    * <h5 class='section'>Property:</h5>
276    * <ul>
277    *    <li><b>Name:</b>  <js>"XmlSerializer.namespaces.ls"</js>
278    *    <li><b>Data type:</b>  <code>Set&lt;String&gt;</code> ({@link Namespace})
279    *    <li><b>Default:</b>  empty set
280    *    <li><b>Session-overridable:</b>  <jk>true</jk>
281    *    <li><b>Methods:</b> 
282    *       <ul>
283    *          <li class='jm'>{@link XmlSerializerBuilder#defaultNamespace(String)}
284    *       </ul>
285    * </ul>
286    * 
287    * <h5 class='section'>Description:</h5>
288    * <p>
289    * The default list of namespaces associated with this serializer.
290    * 
291    * <h5 class='section'>See Also:</h5>
292    * <ul>
293    *    <li class='link'><a class="doclink" href="package-summary.html#Namespaces">org.apache.juneau.xml &gt; Namespaces</a>
294    * </ul>
295    */
296   public static final String XML_namespaces = PREFIX + "namespaces.ls";
297
298   /**
299    * Configuration property:  XMLSchema namespace.
300    * 
301    * <h5 class='section'>Property:</h5>
302    * <ul>
303    *    <li><b>Name:</b>  <js>"XmlSerializer.xsNamespace.s"</js>
304    *    <li><b>Data type:</b>  <code>String</code> ({@link Namespace})
305    *    <li><b>Default:</b>  <js>"xs: http://www.w3.org/2001/XMLSchema"</js>
306    *    <li><b>Session-overridable:</b>  <jk>true</jk>
307    *    <li><b>Methods:</b> 
308    *       <ul>
309    *          <li class='jm'>{@link XmlSerializerBuilder#xsNamespace(Namespace)}
310    *       </ul>
311    * </ul>
312    * 
313    * <h5 class='section'>Description:</h5>
314    * <p>
315    * Specifies the namespace for the <code>XMLSchema</code> namespace, used by the schema generated by the
316    * {@link XmlSchemaSerializer} class.
317    * 
318    * <h5 class='section'>See Also:</h5>
319    * <ul>
320    *    <li class='link'><a class="doclink" href="package-summary.html#Namespaces">org.apache.juneau.xml &gt; Namespaces</a>
321    * </ul>
322    */
323   public static final String XML_xsNamespace = PREFIX + "xsNamespace.s";
324
325
326   //-------------------------------------------------------------------------------------------------------------------
327   // Predefined instances
328   //-------------------------------------------------------------------------------------------------------------------
329
330   /** Default serializer without namespaces. */
331   public static final XmlSerializer DEFAULT = new XmlSerializer(PropertyStore.DEFAULT);
332
333   /** Default serializer without namespaces, with single quotes. */
334   public static final XmlSerializer DEFAULT_SQ = new Sq(PropertyStore.DEFAULT);
335
336   /** Default serializer without namespaces, with single quotes, whitespace added. */
337   public static final XmlSerializer DEFAULT_SQ_READABLE = new SqReadable(PropertyStore.DEFAULT);
338
339   /** Default serializer, all default settings. */
340   public static final XmlSerializer DEFAULT_NS = new Ns(PropertyStore.DEFAULT);
341
342   /** Default serializer, single quotes. */
343   public static final XmlSerializer DEFAULT_NS_SQ = new NsSq(PropertyStore.DEFAULT);
344
345   /** Default serializer, single quotes, whitespace added. */
346   public static final XmlSerializer DEFAULT_NS_SQ_READABLE = new NsSqReadable(PropertyStore.DEFAULT);
347
348
349   //-------------------------------------------------------------------------------------------------------------------
350   // Predefined subclasses
351   //-------------------------------------------------------------------------------------------------------------------
352
353   /** Default serializer, single quotes. */
354   public static class Sq extends XmlSerializer {
355
356      /**
357       * Constructor.
358       * 
359       * @param ps The property store containing all the settings for this object.
360       */
361      public Sq(PropertyStore ps) {
362         super(
363            ps.builder()
364               .set(SERIALIZER_quoteChar, '\'')
365               .build()
366            );
367      }
368   }
369
370   /** Default serializer, single quotes, whitespace added. */
371   public static class SqReadable extends XmlSerializer {
372
373      /**
374       * Constructor.
375       * 
376       * @param ps The property store containing all the settings for this object.
377       */
378      public SqReadable(PropertyStore ps) {
379         super(
380            ps.builder()
381               .set(SERIALIZER_quoteChar, '\'')
382               .set(SERIALIZER_useWhitespace, true)
383               .build()
384            );
385      }
386   }
387
388   /** Default serializer without namespaces. */
389   public static class Ns extends XmlSerializer {
390
391      /**
392       * Constructor.
393       * 
394       * @param ps The property store containing all the settings for this object.
395       */
396      public Ns(PropertyStore ps) {
397         super(
398            ps.builder()
399               .set(XML_enableNamespaces, true)
400               .build(),
401            "text/xml", 
402            "text/xml+simple"
403         );
404      }
405   }
406
407   /** Default serializer without namespaces, single quotes. */
408   public static class NsSq extends XmlSerializer {
409
410      /**
411       * Constructor.
412       * 
413       * @param ps The property store containing all the settings for this object.
414       */
415      public NsSq(PropertyStore ps) {
416         super(
417            ps.builder()
418               .set(XML_enableNamespaces, true)
419               .set(SERIALIZER_quoteChar, '\'')
420               .build()
421            );
422      }
423   }
424
425   /** Default serializer without namespaces, single quotes, with whitespace. */
426   public static class NsSqReadable extends XmlSerializer {
427
428      /**
429       * Constructor.
430       * 
431       * @param ps The property store containing all the settings for this object.
432       */
433      public NsSqReadable(PropertyStore ps) {
434         super(
435            ps.builder()
436               .set(XML_enableNamespaces, true)
437               .set(SERIALIZER_quoteChar, '\'')
438               .set(SERIALIZER_useWhitespace, true)
439               .build()
440            );
441      }
442   }
443
444   private static final Namespace 
445      DEFAULT_JUNEAU_NAMESPACE = Namespace.create("juneau", "http://www.apache.org/2013/Juneau"),
446      DEFAULT_XS_NAMESPACE = Namespace.create("xs", "http://www.w3.org/2001/XMLSchema");
447   
448   //-------------------------------------------------------------------------------------------------------------------
449   // Instance
450   //-------------------------------------------------------------------------------------------------------------------
451
452   final boolean
453      autoDetectNamespaces,
454      enableNamespaces,
455      addNamespaceUrlsToRoot,
456      addBeanTypeProperties;
457   
458   final Namespace defaultNamespace;
459   
460   final Namespace
461      xsNamespace;
462   
463   final Namespace[] namespaces;
464
465   private volatile XmlSchemaSerializer schemaSerializer;
466
467   /**
468    * Constructor.
469    * 
470    * @param ps
471    *    The property store containing all the settings for this object.
472    */
473   public XmlSerializer(PropertyStore ps) {
474      this(ps, "text/xml");
475   }
476
477   /**
478    * Constructor.
479    * 
480    * @param ps
481    *    The property store containing all the settings for this object.
482    * @param produces
483    *    The media type that this serializer produces.
484    * @param accept
485    *    The accept media types that the serializer can handle.
486    *    <p>
487    *    Can contain meta-characters per the <code>media-type</code> specification of
488    *    <a class="doclink" href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1">RFC2616/14.1</a>
489    *    <p>
490    *    If empty, then assumes the only media type supported is <code>produces</code>.
491    *    <p>
492    *    For example, if this serializer produces <js>"application/json"</js> but should handle media types of
493    *    <js>"application/json"</js> and <js>"text/json"</js>, then the arguments should be:
494    *    <p class='bcode'>
495    *    <jk>super</jk>(ps, <js>"application/json"</js>, <js>"application/json"</js>, <js>"text/json"</js>);
496    *    </p>
497    *    <br>...or...
498    *    <p class='bcode'>
499    *    <jk>super</jk>(ps, <js>"application/json"</js>, <js>"*&#8203;/json"</js>);
500    *    </p>
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      addBeanTypeProperties = getBooleanProperty(XML_addBeanTypeProperties, getBooleanProperty(SERIALIZER_addBeanTypeProperties, true));
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   @Override /* Context */
550   public ObjectMap asMap() {
551      return super.asMap()
552         .append("XmlSerializer", new ObjectMap()
553            .append("autoDetectNamespaces", autoDetectNamespaces)
554            .append("enableNamespaces", enableNamespaces)
555            .append("addNamespaceUrlsToRoot", addNamespaceUrlsToRoot)
556            .append("defaultNamespace", defaultNamespace)
557            .append("xsNamespace", xsNamespace)
558            .append("namespaces", namespaces)
559            .append("addBeanTypeProperties", addBeanTypeProperties)
560         );
561   }
562}