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 static org.apache.juneau.collections.JsonMap.*;
016import static org.apache.juneau.internal.CollectionUtils.*;
017
018import java.lang.annotation.*;
019import java.lang.reflect.*;
020import java.nio.charset.*;
021import java.util.*;
022import java.util.concurrent.*;
023
024import org.apache.juneau.*;
025import org.apache.juneau.collections.*;
026import org.apache.juneau.internal.*;
027import org.apache.juneau.json.*;
028import org.apache.juneau.serializer.*;
029import org.apache.juneau.utils.*;
030
031/**
032 * Serializes POJO models to XML.
033 *
034 * <h5 class='topic'>Media types</h5>
035 * <p>
036 * Handles <c>Accept</c> types:  <bc>text/xml</bc>
037 * <p>
038 * Produces <c>Content-Type</c> types:  <bc>text/xml</bc>
039 *
040 * <h5 class='topic'>Description</h5>
041 * <p>
042 * See the {@link JsonSerializer} class for details on how Java models map to JSON.
043 *
044 * <p>
045 * For example, the following JSON...
046 * <p class='bjson'>
047 *    {
048 *       name:<js>'John Smith'</js>,
049 *       address: {
050 *          streetAddress: <js>'21 2nd Street'</js>,
051 *          city: <js>'New York'</js>,
052 *          state: <js>'NY'</js>,
053 *          postalCode: <js>10021</js>
054 *       },
055 *       phoneNumbers: [
056 *          <js>'212 555-1111'</js>,
057 *          <js>'212 555-2222'</js>
058 *       ],
059 *       additionalInfo: <jk>null</jk>,
060 *       remote: <jk>false</jk>,
061 *       height: <js>62.4</js>,
062 *       <js>'fico score'</js>:  <js>' &gt; 640'</js>
063 *    }
064 * <p>
065 *    ...maps to the following XML using the default serializer...
066 * <p class='bxml'>
067 *    <xt>&lt;object&gt;</xt>
068 *       <xt>&lt;name&gt;</xt>John Smith<xt>&lt;/name&gt;</xt>
069 *       <xt>&lt;address&gt;</xt>
070 *          <xt>&lt;streetAddress&gt;</xt>21 2nd Street<xt>&lt;/streetAddress&gt;</xt>
071 *          <xt>&lt;city&gt;</xt>New York<xt>&lt;/city&gt;</xt>
072 *          <xt>&lt;state&gt;</xt>NY<xt>&lt;/state&gt;</xt>
073 *          <xt>&lt;postalCode&gt;</xt>10021<xt>&lt;/postalCode&gt;</xt>
074 *       <xt>&lt;/address&gt;</xt>
075 *       <xt>&lt;phoneNumbers&gt;</xt>
076 *          <xt>&lt;string&gt;</xt>212 555-1111<xt>&lt;/string&gt;</xt>
077 *          <xt>&lt;string&gt;</xt>212 555-2222<xt>&lt;/string&gt;</xt>
078 *       <xt>&lt;/phoneNumbers&gt;</xt>
079 *       <xt>&lt;additionalInfo</xt> <xa>_type</xa>=<xs>'null'</xs><xt>&gt;&lt;/additionalInfo&gt;</xt>
080 *       <xt>&lt;remote&gt;</xt>false<xt>&lt;/remote&gt;</xt>
081 *       <xt>&lt;height&gt;</xt>62.4<xt>&lt;/height&gt;</xt>
082 *       <xt>&lt;fico_x0020_score&gt;</xt> &amp;gt; 640<xt>&lt;/fico_x0020_score&gt;</xt>
083 *    <xt>&lt;/object&gt;</xt>
084 *
085 * <p>
086 * An additional "add-json-properties" mode is also provided to prevent loss of JSON data types...
087 * <p class='bxml'>
088 *    <xt>&lt;object&gt;</xt>
089 *       <xt>&lt;name</xt> <xa>_type</xa>=<xs>'string'</xs><xt>&gt;</xt>John Smith<xt>&lt;/name&gt;</xt>
090 *       <xt>&lt;address</xt> <xa>_type</xa>=<xs>'object'</xs><xt>&gt;</xt>
091 *          <xt>&lt;streetAddress</xt> <xa>_type</xa>=<xs>'string'</xs><xt>&gt;</xt>21 2nd Street<xt>&lt;/streetAddress&gt;</xt>
092 *          <xt>&lt;city</xt> <xa>_type</xa>=<xs>'string'</xs><xt>&gt;</xt>New York<xt>&lt;/city&gt;</xt>
093 *          <xt>&lt;state</xt> <xa>_type</xa>=<xs>'string'</xs><xt>&gt;</xt>NY<xt>&lt;/state&gt;</xt>
094 *          <xt>&lt;postalCode</xt> <xa>_type</xa>=<xs>'number'</xs><xt>&gt;</xt>10021<xt>&lt;/postalCode&gt;</xt>
095 *       <xt>&lt;/address&gt;</xt>
096 *       <xt>&lt;phoneNumbers</xt> <xa>_type</xa>=<xs>'array'</xs><xt>&gt;</xt>
097 *          <xt>&lt;string&gt;</xt>212 555-1111<xt>&lt;/string&gt;</xt>
098 *          <xt>&lt;string&gt;</xt>212 555-2222<xt>&lt;/string&gt;</xt>
099 *       <xt>&lt;/phoneNumbers&gt;</xt>
100 *       <xt>&lt;additionalInfo</xt> <xa>_type</xa>=<xs>'null'</xs><xt>&gt;&lt;/additionalInfo&gt;</xt>
101 *       <xt>&lt;remote</xt> <xa>_type</xa>=<xs>'boolean'</xs><xt>&gt;</xt>false<xt>&lt;/remote&gt;</xt>
102 *       <xt>&lt;height</xt> <xa>_type</xa>=<xs>'number'</xs><xt>&gt;</xt>62.4<xt>&lt;/height&gt;</xt>
103 *       <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>
104 *    <xt>&lt;/object&gt;</xt>
105 * </p>
106 *
107 * <p>
108 * This serializer provides several serialization options.
109 * Typically, one of the predefined <jsf>DEFAULT</jsf> serializers will be sufficient.
110 * However, custom serializers can be constructed to fine-tune behavior.
111 *
112 * <p>
113 * If an attribute name contains any non-valid XML element characters, they will be escaped using standard
114 * {@code _x####_} notation.
115 *
116 * <h5 class='topic'>Behavior-specific subclasses</h5>
117 * <p>
118 * The following direct subclasses are provided for convenience:
119 * <ul>
120 *    <li>{@link Sq} - Default serializer, single quotes.
121 *    <li>{@link SqReadable} - Default serializer, single quotes, whitespace added.
122 * </ul>
123 *
124 * <h5 class='section'>Notes:</h5><ul>
125 *    <li class='note'>This class is thread safe and reusable.
126 * </ul>
127 *
128 * <h5 class='section'>See Also:</h5><ul>
129 *    <li class='link'><a class="doclink" href="../../../../index.html#jm.XmlDetails">XML Details</a>
130
131 * </ul>
132 */
133public class XmlSerializer extends WriterSerializer implements XmlMetaProvider {
134
135   //-------------------------------------------------------------------------------------------------------------------
136   // Static
137   //-------------------------------------------------------------------------------------------------------------------
138
139   private static final Namespace[] EMPTY_NAMESPACE_ARRAY = {};
140
141   /** Default serializer without namespaces. */
142   public static final XmlSerializer DEFAULT = new XmlSerializer(create());
143
144   /** Default serializer without namespaces, with single quotes. */
145   public static final XmlSerializer DEFAULT_SQ = new Sq(create());
146
147   /** Default serializer without namespaces, with single quotes, whitespace added. */
148   public static final XmlSerializer DEFAULT_SQ_READABLE = new SqReadable(create());
149
150   /** Default serializer, all default settings. */
151   public static final XmlSerializer DEFAULT_NS = new Ns(create());
152
153   /** Default serializer, single quotes. */
154   public static final XmlSerializer DEFAULT_NS_SQ = new NsSq(create());
155
156   /** Default serializer, single quotes, whitespace added. */
157   public static final XmlSerializer DEFAULT_NS_SQ_READABLE = new NsSqReadable(create());
158
159   /**
160    * Creates a new builder for this object.
161    *
162    * @return A new builder.
163    */
164   public static Builder create() {
165      return new Builder();
166   }
167
168   //-------------------------------------------------------------------------------------------------------------------
169   // Static subclasses
170   //-------------------------------------------------------------------------------------------------------------------
171
172   /** Default serializer, single quotes. */
173   public static class Sq extends XmlSerializer {
174
175      /**
176       * Constructor.
177       *
178       * @param builder The builder for this object.
179       */
180      public Sq(Builder builder) {
181         super(builder.quoteChar('\''));
182      }
183   }
184
185   /** Default serializer, single quotes, whitespace added. */
186   public static class SqReadable extends XmlSerializer {
187
188      /**
189       * Constructor.
190       *
191       * @param builder The builder for this object.
192       */
193      public SqReadable(Builder builder) {
194         super(builder.quoteChar('\'').useWhitespace());
195      }
196   }
197
198   /** Default serializer without namespaces. */
199   public static class Ns extends XmlSerializer {
200
201      /**
202       * Constructor.
203       *
204       * @param builder The builder for this object.
205       */
206      public Ns(Builder builder) {
207         super(builder.enableNamespaces());
208      }
209   }
210
211   /** Default serializer without namespaces, single quotes. */
212   public static class NsSq extends XmlSerializer {
213
214      /**
215       * Constructor.
216       *
217       * @param builder The builder for this object.
218       */
219      public NsSq(Builder builder) {
220         super(builder.enableNamespaces().quoteChar('\''));
221      }
222   }
223
224   /** Default serializer without namespaces, single quotes, with whitespace. */
225   public static class NsSqReadable extends XmlSerializer {
226
227      /**
228       * Constructor.
229       *
230       * @param builder The builder for this object.
231       */
232      public NsSqReadable(Builder builder) {
233         super(builder.enableNamespaces().quoteChar('\'').useWhitespace());
234      }
235   }
236
237   @SuppressWarnings("javadoc")
238   protected static final Namespace
239      DEFAULT_JUNEAU_NAMESPACE = Namespace.of("juneau", "http://www.apache.org/2013/Juneau"),
240      DEFAULT_XS_NAMESPACE = Namespace.of("xs", "http://www.w3.org/2001/XMLSchema");
241
242   //-------------------------------------------------------------------------------------------------------------------
243   // Builder
244   //-------------------------------------------------------------------------------------------------------------------
245
246   /**
247    * Builder class.
248    */
249   @FluentSetters
250   public static class Builder extends WriterSerializer.Builder {
251
252      private static final Cache<HashKey,XmlSerializer> CACHE = Cache.of(HashKey.class, XmlSerializer.class).build();
253
254      boolean addBeanTypesXml, addNamespaceUrisToRoot, disableAutoDetectNamespaces, enableNamespaces;
255      Namespace defaultNamespace;
256      List<Namespace> namespaces;
257
258      /**
259       * Constructor, default settings.
260       */
261      protected Builder() {
262         produces("text/xml");
263         addBeanTypesXml = env("XmlSerializer.addBeanTypes", false);
264         addNamespaceUrisToRoot = env("XmlSerializer.addNamespaceUrisToRoot", false);
265         disableAutoDetectNamespaces = env("XmlSerializer.disableAutoDetectNamespaces", false);
266         enableNamespaces = env("XmlSerializer.enableNamespaces", false);
267         defaultNamespace = null;
268         namespaces = null;
269
270      }
271
272      /**
273       * Copy constructor.
274       *
275       * @param copyFrom The bean to copy from.
276       */
277      protected Builder(XmlSerializer copyFrom) {
278         super(copyFrom);
279         addBeanTypesXml = copyFrom.addBeanTypesXml;
280         addNamespaceUrisToRoot = copyFrom.addNamespaceUrlsToRoot;
281         disableAutoDetectNamespaces = ! copyFrom.autoDetectNamespaces;
282         enableNamespaces = copyFrom.enableNamespaces;
283         defaultNamespace = copyFrom.defaultNamespace;
284         namespaces = copyFrom.namespaces.length == 0 ? null : list(copyFrom.namespaces);
285      }
286
287      /**
288       * Copy constructor.
289       *
290       * @param copyFrom The builder to copy from.
291       */
292      protected Builder(Builder copyFrom) {
293         super(copyFrom);
294         addBeanTypesXml = copyFrom.addBeanTypesXml;
295         addNamespaceUrisToRoot = copyFrom.addNamespaceUrisToRoot;
296         disableAutoDetectNamespaces = copyFrom.disableAutoDetectNamespaces;
297         enableNamespaces = copyFrom.enableNamespaces;
298         defaultNamespace = copyFrom.defaultNamespace;
299         namespaces = copyOf(copyFrom.namespaces);
300      }
301
302      @Override /* Context.Builder */
303      public Builder copy() {
304         return new Builder(this);
305      }
306
307      @Override /* Context.Builder */
308      public XmlSerializer build() {
309         return cache(CACHE).build(XmlSerializer.class);
310      }
311
312      @Override /* Context.Builder */
313      public HashKey hashKey() {
314         return HashKey.of(
315            super.hashKey(),
316            addBeanTypesXml,
317            addNamespaceUrisToRoot,
318            disableAutoDetectNamespaces,
319            enableNamespaces,
320            defaultNamespace,
321            namespaces
322         );
323      }
324
325      //-----------------------------------------------------------------------------------------------------------------
326      // Properties
327      //-----------------------------------------------------------------------------------------------------------------
328
329      /**
330       * Add <js>"_type"</js> properties when needed.
331       *
332       * <p>
333       * If <jk>true</jk>, then <js>"_type"</js> properties will be added to beans if their type cannot be inferred
334       * through reflection.
335       *
336       * <p>
337       * When present, this value overrides the {@link org.apache.juneau.serializer.Serializer.Builder#addBeanTypes()} setting and is
338       * provided to customize the behavior of specific serializers in a {@link SerializerSet}.
339       *
340       * @return This object.
341       */
342      @FluentSetter
343      public Builder addBeanTypesXml() {
344         return addBeanTypesXml(true);
345      }
346
347      /**
348       * Same as {@link #addBeanTypesXml()} but allows you to explicitly specify the value.
349       *
350       * @param value The value for this setting.
351       * @return This object.
352       */
353      @FluentSetter
354      public Builder addBeanTypesXml(boolean value) {
355         addBeanTypesXml = value;
356         return this;
357      }
358
359      /**
360       * Add namespace URLs to the root element.
361       *
362       * <p>
363       * Use this setting to add {@code xmlns:x} attributes to the root element for the default and all mapped namespaces.
364       *
365       * <p>
366       * This setting is ignored if {@link #enableNamespaces()} is not enabled.
367       *
368       * <h5 class='section'>See Also:</h5><ul>
369       *    <li class='link'><a class="doclink" href="../../../../index.html#jm.XmlNamespaces">Namespaces</a>
370       * </ul>
371       *
372       * @return This object.
373       */
374      @FluentSetter
375      public Builder addNamespaceUrisToRoot() {
376         return addNamespaceUrisToRoot(true);
377      }
378
379      /**
380       * Same as {@link #addNamespaceUrisToRoot()} but allows you to explicitly specify the value.
381       *
382       * @param value The value for this setting.
383       * @return This object.
384       */
385      @FluentSetter
386      public Builder addNamespaceUrisToRoot(boolean value) {
387         addNamespaceUrisToRoot = value;
388         return this;
389      }
390
391      /**
392       * Don't auto-detect namespace usage.
393       *
394       * <p>
395       * Don't detect namespace usage before serialization.
396       *
397       * <p>
398       * Used in conjunction with {@link Builder#addNamespaceUrisToRoot()} to reduce the list of namespace URLs appended to the
399       * root element to only those that will be used in the resulting document.
400       *
401       * <p>
402       * If disabled, then the data structure will first be crawled looking for namespaces that will be encountered before
403       * the root element is serialized.
404       *
405       * <p>
406       * This setting is ignored if {@link Builder#enableNamespaces()} is not enabled.
407       *
408       * <h5 class='section'>Notes:</h5><ul>
409       *    <li class='note'>
410       *       Auto-detection of namespaces can be costly performance-wise.
411       *       <br>In high-performance environments, it's recommended that namespace detection be
412       *       disabled, and that namespaces be manually defined through the {@link Builder#namespaces(Namespace...)} property.
413       * </ul>
414       *
415       * <h5 class='section'>See Also:</h5><ul>
416       *    <li class='link'><a class="doclink" href="../../../../index.html#jm.XmlNamespaces">Namespaces</a>
417       * </ul>
418       *
419       * @return This object.
420       */
421      @FluentSetter
422      public Builder disableAutoDetectNamespaces() {
423         return disableAutoDetectNamespaces(true);
424      }
425
426      /**
427       * Same as {@link #disableAutoDetectNamespaces()} but allows you to explicitly specify the value.
428       *
429       * @param value The value for this setting.
430       * @return This object.
431       */
432      @FluentSetter
433      public Builder disableAutoDetectNamespaces(boolean value) {
434         disableAutoDetectNamespaces = value;
435         return this;
436      }
437
438      /**
439       * Default namespace.
440       *
441       * <p>
442       * Specifies the default namespace URI for this document.
443       *
444       * <h5 class='section'>See Also:</h5><ul>
445       *    <li class='link'><a class="doclink" href="../../../../index.html#jm.XmlNamespaces">Namespaces</a>
446       * </ul>
447       *
448       * @param value
449       *    The new value for this property.
450       *    <br>The default is <js>"juneau: http://www.apache.org/2013/Juneau"</js>.
451       * @return This object.
452       */
453      @FluentSetter
454      public Builder defaultNamespace(Namespace value) {
455         defaultNamespace = value;
456         return this;
457      }
458
459      /**
460       * Enable support for XML namespaces.
461       *
462       * <p>
463       * If not enabled, XML output will not contain any namespaces regardless of any other settings.
464       *
465       * <h5 class='section'>See Also:</h5><ul>
466       *    <li class='link'><a class="doclink" href="../../../../index.html#jm.XmlNamespaces">Namespaces</a>
467       * </ul>
468       *
469       * @return This object.
470       */
471      @FluentSetter
472      public Builder enableNamespaces() {
473         return enableNamespaces(true);
474      }
475
476      /**
477       * Same as {@link #enableNamespaces()} but allows you to explicitly specify the value.
478       *
479       * @param value The value for this setting.
480       * @return This object.
481       */
482      @FluentSetter
483      public Builder enableNamespaces(boolean value) {
484         enableNamespaces = value;
485         return this;
486      }
487
488      /**
489       * Enable support for XML namespaces.
490       *
491       * <p>
492       * Shortcut for calling <code>enableNamespaces(<jk>true</jk>)</code>.
493       *
494       * @return This object.
495       */
496      @FluentSetter
497      public Builder ns() {
498         return enableNamespaces();
499      }
500
501      /**
502       * Default namespaces.
503       *
504       * <p>
505       * The default list of namespaces associated with this serializer.
506       *
507       * @param values The new value for this property.
508       * @return This object.
509       */
510      @FluentSetter
511      public Builder namespaces(Namespace...values) {
512         namespaces = addAll(namespaces, values);
513         return this;
514      }
515
516      // <FluentSetters>
517
518      @Override /* GENERATED - org.apache.juneau.Context.Builder */
519      public Builder annotations(Annotation...values) {
520         super.annotations(values);
521         return this;
522      }
523
524      @Override /* GENERATED - org.apache.juneau.Context.Builder */
525      public Builder apply(AnnotationWorkList work) {
526         super.apply(work);
527         return this;
528      }
529
530      @Override /* GENERATED - org.apache.juneau.Context.Builder */
531      public Builder applyAnnotations(java.lang.Class<?>...fromClasses) {
532         super.applyAnnotations(fromClasses);
533         return this;
534      }
535
536      @Override /* GENERATED - org.apache.juneau.Context.Builder */
537      public Builder applyAnnotations(Method...fromMethods) {
538         super.applyAnnotations(fromMethods);
539         return this;
540      }
541
542      @Override /* GENERATED - org.apache.juneau.Context.Builder */
543      public Builder cache(Cache<HashKey,? extends org.apache.juneau.Context> value) {
544         super.cache(value);
545         return this;
546      }
547
548      @Override /* GENERATED - org.apache.juneau.Context.Builder */
549      public Builder debug() {
550         super.debug();
551         return this;
552      }
553
554      @Override /* GENERATED - org.apache.juneau.Context.Builder */
555      public Builder debug(boolean value) {
556         super.debug(value);
557         return this;
558      }
559
560      @Override /* GENERATED - org.apache.juneau.Context.Builder */
561      public Builder impl(Context value) {
562         super.impl(value);
563         return this;
564      }
565
566      @Override /* GENERATED - org.apache.juneau.Context.Builder */
567      public Builder type(Class<? extends org.apache.juneau.Context> value) {
568         super.type(value);
569         return this;
570      }
571
572      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
573      public Builder beanClassVisibility(Visibility value) {
574         super.beanClassVisibility(value);
575         return this;
576      }
577
578      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
579      public Builder beanConstructorVisibility(Visibility value) {
580         super.beanConstructorVisibility(value);
581         return this;
582      }
583
584      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
585      public Builder beanContext(BeanContext value) {
586         super.beanContext(value);
587         return this;
588      }
589
590      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
591      public Builder beanContext(BeanContext.Builder value) {
592         super.beanContext(value);
593         return this;
594      }
595
596      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
597      public Builder beanDictionary(java.lang.Class<?>...values) {
598         super.beanDictionary(values);
599         return this;
600      }
601
602      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
603      public Builder beanFieldVisibility(Visibility value) {
604         super.beanFieldVisibility(value);
605         return this;
606      }
607
608      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
609      public Builder beanInterceptor(Class<?> on, Class<? extends org.apache.juneau.swap.BeanInterceptor<?>> value) {
610         super.beanInterceptor(on, value);
611         return this;
612      }
613
614      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
615      public Builder beanMapPutReturnsOldValue() {
616         super.beanMapPutReturnsOldValue();
617         return this;
618      }
619
620      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
621      public Builder beanMethodVisibility(Visibility value) {
622         super.beanMethodVisibility(value);
623         return this;
624      }
625
626      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
627      public Builder beanProperties(Map<String,Object> values) {
628         super.beanProperties(values);
629         return this;
630      }
631
632      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
633      public Builder beanProperties(Class<?> beanClass, String properties) {
634         super.beanProperties(beanClass, properties);
635         return this;
636      }
637
638      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
639      public Builder beanProperties(String beanClassName, String properties) {
640         super.beanProperties(beanClassName, properties);
641         return this;
642      }
643
644      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
645      public Builder beanPropertiesExcludes(Map<String,Object> values) {
646         super.beanPropertiesExcludes(values);
647         return this;
648      }
649
650      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
651      public Builder beanPropertiesExcludes(Class<?> beanClass, String properties) {
652         super.beanPropertiesExcludes(beanClass, properties);
653         return this;
654      }
655
656      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
657      public Builder beanPropertiesExcludes(String beanClassName, String properties) {
658         super.beanPropertiesExcludes(beanClassName, properties);
659         return this;
660      }
661
662      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
663      public Builder beanPropertiesReadOnly(Map<String,Object> values) {
664         super.beanPropertiesReadOnly(values);
665         return this;
666      }
667
668      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
669      public Builder beanPropertiesReadOnly(Class<?> beanClass, String properties) {
670         super.beanPropertiesReadOnly(beanClass, properties);
671         return this;
672      }
673
674      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
675      public Builder beanPropertiesReadOnly(String beanClassName, String properties) {
676         super.beanPropertiesReadOnly(beanClassName, properties);
677         return this;
678      }
679
680      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
681      public Builder beanPropertiesWriteOnly(Map<String,Object> values) {
682         super.beanPropertiesWriteOnly(values);
683         return this;
684      }
685
686      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
687      public Builder beanPropertiesWriteOnly(Class<?> beanClass, String properties) {
688         super.beanPropertiesWriteOnly(beanClass, properties);
689         return this;
690      }
691
692      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
693      public Builder beanPropertiesWriteOnly(String beanClassName, String properties) {
694         super.beanPropertiesWriteOnly(beanClassName, properties);
695         return this;
696      }
697
698      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
699      public Builder beansRequireDefaultConstructor() {
700         super.beansRequireDefaultConstructor();
701         return this;
702      }
703
704      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
705      public Builder beansRequireSerializable() {
706         super.beansRequireSerializable();
707         return this;
708      }
709
710      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
711      public Builder beansRequireSettersForGetters() {
712         super.beansRequireSettersForGetters();
713         return this;
714      }
715
716      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
717      public Builder dictionaryOn(Class<?> on, java.lang.Class<?>...values) {
718         super.dictionaryOn(on, values);
719         return this;
720      }
721
722      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
723      public Builder disableBeansRequireSomeProperties() {
724         super.disableBeansRequireSomeProperties();
725         return this;
726      }
727
728      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
729      public Builder disableIgnoreMissingSetters() {
730         super.disableIgnoreMissingSetters();
731         return this;
732      }
733
734      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
735      public Builder disableIgnoreTransientFields() {
736         super.disableIgnoreTransientFields();
737         return this;
738      }
739
740      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
741      public Builder disableIgnoreUnknownNullBeanProperties() {
742         super.disableIgnoreUnknownNullBeanProperties();
743         return this;
744      }
745
746      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
747      public Builder disableInterfaceProxies() {
748         super.disableInterfaceProxies();
749         return this;
750      }
751
752      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
753      public <T> Builder example(Class<T> pojoClass, T o) {
754         super.example(pojoClass, o);
755         return this;
756      }
757
758      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
759      public <T> Builder example(Class<T> pojoClass, String json) {
760         super.example(pojoClass, json);
761         return this;
762      }
763
764      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
765      public Builder findFluentSetters() {
766         super.findFluentSetters();
767         return this;
768      }
769
770      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
771      public Builder findFluentSetters(Class<?> on) {
772         super.findFluentSetters(on);
773         return this;
774      }
775
776      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
777      public Builder ignoreInvocationExceptionsOnGetters() {
778         super.ignoreInvocationExceptionsOnGetters();
779         return this;
780      }
781
782      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
783      public Builder ignoreInvocationExceptionsOnSetters() {
784         super.ignoreInvocationExceptionsOnSetters();
785         return this;
786      }
787
788      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
789      public Builder ignoreUnknownBeanProperties() {
790         super.ignoreUnknownBeanProperties();
791         return this;
792      }
793
794      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
795      public Builder ignoreUnknownEnumValues() {
796         super.ignoreUnknownEnumValues();
797         return this;
798      }
799
800      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
801      public Builder implClass(Class<?> interfaceClass, Class<?> implClass) {
802         super.implClass(interfaceClass, implClass);
803         return this;
804      }
805
806      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
807      public Builder implClasses(Map<Class<?>,Class<?>> values) {
808         super.implClasses(values);
809         return this;
810      }
811
812      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
813      public Builder interfaceClass(Class<?> on, Class<?> value) {
814         super.interfaceClass(on, value);
815         return this;
816      }
817
818      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
819      public Builder interfaces(java.lang.Class<?>...value) {
820         super.interfaces(value);
821         return this;
822      }
823
824      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
825      public Builder locale(Locale value) {
826         super.locale(value);
827         return this;
828      }
829
830      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
831      public Builder mediaType(MediaType value) {
832         super.mediaType(value);
833         return this;
834      }
835
836      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
837      public Builder notBeanClasses(java.lang.Class<?>...values) {
838         super.notBeanClasses(values);
839         return this;
840      }
841
842      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
843      public Builder notBeanPackages(String...values) {
844         super.notBeanPackages(values);
845         return this;
846      }
847
848      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
849      public Builder propertyNamer(Class<? extends org.apache.juneau.PropertyNamer> value) {
850         super.propertyNamer(value);
851         return this;
852      }
853
854      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
855      public Builder propertyNamer(Class<?> on, Class<? extends org.apache.juneau.PropertyNamer> value) {
856         super.propertyNamer(on, value);
857         return this;
858      }
859
860      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
861      public Builder sortProperties() {
862         super.sortProperties();
863         return this;
864      }
865
866      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
867      public Builder sortProperties(java.lang.Class<?>...on) {
868         super.sortProperties(on);
869         return this;
870      }
871
872      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
873      public Builder stopClass(Class<?> on, Class<?> value) {
874         super.stopClass(on, value);
875         return this;
876      }
877
878      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
879      public <T, S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction) {
880         super.swap(normalClass, swappedClass, swapFunction);
881         return this;
882      }
883
884      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
885      public <T, S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction, ThrowingFunction<S,T> unswapFunction) {
886         super.swap(normalClass, swappedClass, swapFunction, unswapFunction);
887         return this;
888      }
889
890      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
891      public Builder swaps(java.lang.Class<?>...values) {
892         super.swaps(values);
893         return this;
894      }
895
896      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
897      public Builder timeZone(TimeZone value) {
898         super.timeZone(value);
899         return this;
900      }
901
902      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
903      public Builder typeName(Class<?> on, String value) {
904         super.typeName(on, value);
905         return this;
906      }
907
908      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
909      public Builder typePropertyName(String value) {
910         super.typePropertyName(value);
911         return this;
912      }
913
914      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
915      public Builder typePropertyName(Class<?> on, String value) {
916         super.typePropertyName(on, value);
917         return this;
918      }
919
920      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
921      public Builder useEnumNames() {
922         super.useEnumNames();
923         return this;
924      }
925
926      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
927      public Builder useJavaBeanIntrospector() {
928         super.useJavaBeanIntrospector();
929         return this;
930      }
931
932      @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */
933      public Builder detectRecursions() {
934         super.detectRecursions();
935         return this;
936      }
937
938      @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */
939      public Builder detectRecursions(boolean value) {
940         super.detectRecursions(value);
941         return this;
942      }
943
944      @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */
945      public Builder ignoreRecursions() {
946         super.ignoreRecursions();
947         return this;
948      }
949
950      @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */
951      public Builder ignoreRecursions(boolean value) {
952         super.ignoreRecursions(value);
953         return this;
954      }
955
956      @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */
957      public Builder initialDepth(int value) {
958         super.initialDepth(value);
959         return this;
960      }
961
962      @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */
963      public Builder maxDepth(int value) {
964         super.maxDepth(value);
965         return this;
966      }
967
968      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
969      public Builder accept(String value) {
970         super.accept(value);
971         return this;
972      }
973
974      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
975      public Builder addBeanTypes() {
976         super.addBeanTypes();
977         return this;
978      }
979
980      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
981      public Builder addBeanTypes(boolean value) {
982         super.addBeanTypes(value);
983         return this;
984      }
985
986      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
987      public Builder addRootType() {
988         super.addRootType();
989         return this;
990      }
991
992      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
993      public Builder addRootType(boolean value) {
994         super.addRootType(value);
995         return this;
996      }
997
998      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
999      public Builder keepNullProperties() {
1000         super.keepNullProperties();
1001         return this;
1002      }
1003
1004      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1005      public Builder keepNullProperties(boolean value) {
1006         super.keepNullProperties(value);
1007         return this;
1008      }
1009
1010      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1011      public Builder listener(Class<? extends org.apache.juneau.serializer.SerializerListener> value) {
1012         super.listener(value);
1013         return this;
1014      }
1015
1016      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1017      public Builder produces(String value) {
1018         super.produces(value);
1019         return this;
1020      }
1021
1022      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1023      public Builder sortCollections() {
1024         super.sortCollections();
1025         return this;
1026      }
1027
1028      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1029      public Builder sortCollections(boolean value) {
1030         super.sortCollections(value);
1031         return this;
1032      }
1033
1034      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1035      public Builder sortMaps() {
1036         super.sortMaps();
1037         return this;
1038      }
1039
1040      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1041      public Builder sortMaps(boolean value) {
1042         super.sortMaps(value);
1043         return this;
1044      }
1045
1046      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1047      public Builder trimEmptyCollections() {
1048         super.trimEmptyCollections();
1049         return this;
1050      }
1051
1052      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1053      public Builder trimEmptyCollections(boolean value) {
1054         super.trimEmptyCollections(value);
1055         return this;
1056      }
1057
1058      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1059      public Builder trimEmptyMaps() {
1060         super.trimEmptyMaps();
1061         return this;
1062      }
1063
1064      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1065      public Builder trimEmptyMaps(boolean value) {
1066         super.trimEmptyMaps(value);
1067         return this;
1068      }
1069
1070      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1071      public Builder trimStrings() {
1072         super.trimStrings();
1073         return this;
1074      }
1075
1076      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1077      public Builder trimStrings(boolean value) {
1078         super.trimStrings(value);
1079         return this;
1080      }
1081
1082      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1083      public Builder uriContext(UriContext value) {
1084         super.uriContext(value);
1085         return this;
1086      }
1087
1088      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1089      public Builder uriRelativity(UriRelativity value) {
1090         super.uriRelativity(value);
1091         return this;
1092      }
1093
1094      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1095      public Builder uriResolution(UriResolution value) {
1096         super.uriResolution(value);
1097         return this;
1098      }
1099
1100      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1101      public Builder fileCharset(Charset value) {
1102         super.fileCharset(value);
1103         return this;
1104      }
1105
1106      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1107      public Builder maxIndent(int value) {
1108         super.maxIndent(value);
1109         return this;
1110      }
1111
1112      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1113      public Builder quoteChar(char value) {
1114         super.quoteChar(value);
1115         return this;
1116      }
1117
1118      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1119      public Builder quoteCharOverride(char value) {
1120         super.quoteCharOverride(value);
1121         return this;
1122      }
1123
1124      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1125      public Builder sq() {
1126         super.sq();
1127         return this;
1128      }
1129
1130      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1131      public Builder streamCharset(Charset value) {
1132         super.streamCharset(value);
1133         return this;
1134      }
1135
1136      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1137      public Builder useWhitespace() {
1138         super.useWhitespace();
1139         return this;
1140      }
1141
1142      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1143      public Builder useWhitespace(boolean value) {
1144         super.useWhitespace(value);
1145         return this;
1146      }
1147
1148      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1149      public Builder ws() {
1150         super.ws();
1151         return this;
1152      }
1153
1154      // </FluentSetters>
1155   }
1156
1157   //-------------------------------------------------------------------------------------------------------------------
1158   // Instance
1159   //-------------------------------------------------------------------------------------------------------------------
1160
1161   final boolean
1162      autoDetectNamespaces,
1163      enableNamespaces,
1164      addNamespaceUrlsToRoot,
1165      addBeanTypesXml;
1166
1167   final Namespace defaultNamespace;
1168   final Namespace[] namespaces;
1169
1170   private final boolean addBeanTypes;
1171   private final Map<ClassMeta<?>,XmlClassMeta> xmlClassMetas = new ConcurrentHashMap<>();
1172   private final Map<BeanMeta<?>,XmlBeanMeta> xmlBeanMetas = new ConcurrentHashMap<>();
1173   private final Map<BeanPropertyMeta,XmlBeanPropertyMeta> xmlBeanPropertyMetas = new ConcurrentHashMap<>();
1174
1175   /**
1176    * Constructor.
1177    *
1178    * @param builder
1179    *    The builder for this object.
1180    */
1181   public XmlSerializer(Builder builder) {
1182      super(builder);
1183      autoDetectNamespaces = ! builder.disableAutoDetectNamespaces;
1184      enableNamespaces = builder.enableNamespaces;
1185      addNamespaceUrlsToRoot = builder.addNamespaceUrisToRoot;
1186      addBeanTypesXml = builder.addBeanTypesXml;
1187      defaultNamespace = builder.defaultNamespace != null ? builder.defaultNamespace : DEFAULT_JUNEAU_NAMESPACE;
1188      namespaces = builder.namespaces != null ? builder.namespaces.toArray(EMPTY_NAMESPACE_ARRAY) : EMPTY_NAMESPACE_ARRAY;
1189      addBeanTypes = addBeanTypesXml || super.isAddBeanTypes();
1190   }
1191
1192   @Override /* Context */
1193   public Builder copy() {
1194      return new Builder(this);
1195   }
1196
1197   @Override /* Context */
1198   public XmlSerializerSession.Builder createSession() {
1199      return XmlSerializerSession.create(this);
1200   }
1201
1202   @Override /* Context */
1203   public XmlSerializerSession getSession() {
1204      return createSession().build();
1205   }
1206
1207   //-----------------------------------------------------------------------------------------------------------------
1208   // Extended metadata
1209   //-----------------------------------------------------------------------------------------------------------------
1210
1211   @Override /* XmlMetaProvider */
1212   public XmlClassMeta getXmlClassMeta(ClassMeta<?> cm) {
1213      XmlClassMeta m = xmlClassMetas.get(cm);
1214      if (m == null) {
1215         m = new XmlClassMeta(cm, this);
1216         xmlClassMetas.put(cm, m);
1217      }
1218      return m;
1219   }
1220
1221   @Override /* XmlMetaProvider */
1222   public XmlBeanMeta getXmlBeanMeta(BeanMeta<?> bm) {
1223      XmlBeanMeta m = xmlBeanMetas.get(bm);
1224      if (m == null) {
1225         m = new XmlBeanMeta(bm, this);
1226         xmlBeanMetas.put(bm, m);
1227      }
1228      return m;
1229   }
1230
1231   @Override /* XmlMetaProvider */
1232   public XmlBeanPropertyMeta getXmlBeanPropertyMeta(BeanPropertyMeta bpm) {
1233      XmlBeanPropertyMeta m = xmlBeanPropertyMetas.get(bpm);
1234      if (m == null) {
1235         m = new XmlBeanPropertyMeta(bpm.getDelegateFor(), this);
1236         xmlBeanPropertyMetas.put(bpm, m);
1237      }
1238      return m;
1239   }
1240
1241   //-----------------------------------------------------------------------------------------------------------------
1242   // Properties
1243   //-----------------------------------------------------------------------------------------------------------------
1244
1245   /**
1246    * Add <js>"_type"</js> properties when needed.
1247    *
1248    * @see Builder#addBeanTypesXml()
1249    * @return
1250    *    <jk>true</jk> if<js>"_type"</js> properties will be added to beans if their type cannot be inferred
1251    *    through reflection.
1252    */
1253   @Override
1254   protected boolean isAddBeanTypes() {
1255      return addBeanTypes;
1256   }
1257
1258   /**
1259    * Add namespace URLs to the root element.
1260    *
1261    * @see Builder#addNamespaceUrisToRoot()
1262    * @return
1263    *    <jk>true</jk> if {@code xmlns:x} attributes are added to the root element for the default and all mapped namespaces.
1264    */
1265   protected final boolean isAddNamespaceUrlsToRoot() {
1266      return addNamespaceUrlsToRoot;
1267   }
1268
1269   /**
1270    * Auto-detect namespace usage.
1271    *
1272    * @see Builder#disableAutoDetectNamespaces()
1273    * @return
1274    *    <jk>true</jk> if namespace usage is detected before serialization.
1275    */
1276   protected final boolean isAutoDetectNamespaces() {
1277      return autoDetectNamespaces;
1278   }
1279
1280   /**
1281    * Default namespace.
1282    *
1283    * @see Builder#defaultNamespace(Namespace)
1284    * @return
1285    *    The default namespace URI for this document.
1286    */
1287   protected final Namespace getDefaultNamespace() {
1288      return defaultNamespace;
1289   }
1290
1291   /**
1292    * Enable support for XML namespaces.
1293    *
1294    * @see Builder#enableNamespaces()
1295    * @return
1296    *    <jk>false</jk> if XML output will not contain any namespaces regardless of any other settings.
1297    */
1298   protected final boolean isEnableNamespaces() {
1299      return enableNamespaces;
1300   }
1301
1302   /**
1303    * Default namespaces.
1304    *
1305    * @see Builder#namespaces(Namespace...)
1306    * @return
1307    *    The default list of namespaces associated with this serializer.
1308    */
1309   protected final Namespace[] getNamespaces() {
1310      return namespaces;
1311   }
1312
1313   //-----------------------------------------------------------------------------------------------------------------
1314   // Other methods
1315   //-----------------------------------------------------------------------------------------------------------------
1316
1317   @Override /* Context */
1318   protected JsonMap properties() {
1319      return filteredMap()
1320         .append("autoDetectNamespaces", autoDetectNamespaces)
1321         .append("enableNamespaces", enableNamespaces)
1322         .append("addNamespaceUrlsToRoot", addNamespaceUrlsToRoot)
1323         .append("defaultNamespace", defaultNamespace)
1324         .append("namespaces", namespaces)
1325         .append("addBeanTypes", addBeanTypes);
1326   }
1327}