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.uon;
014
015import static org.apache.juneau.collections.JsonMap.*;
016import java.lang.annotation.*;
017import java.lang.reflect.*;
018import java.nio.charset.*;
019import java.util.*;
020import java.util.concurrent.*;
021
022import org.apache.juneau.*;
023import org.apache.juneau.collections.*;
024import org.apache.juneau.httppart.*;
025import org.apache.juneau.internal.*;
026import org.apache.juneau.serializer.*;
027import org.apache.juneau.utils.*;
028
029/**
030 * Serializes POJO models to UON (a notation for URL-encoded query parameter values).
031 *
032 * <h5 class='topic'>Media types</h5>
033 * <p>
034 * Handles <c>Accept</c> types:  <bc>text/uon</bc>
035 * <p>
036 * Produces <c>Content-Type</c> types:  <bc>text/uon</bc>
037 *
038 * <h5 class='topic'>Description</h5>
039 * <p>
040 * This serializer provides several serialization options.
041 * Typically, one of the predefined DEFAULT serializers will be sufficient.
042 * However, custom serializers can be constructed to fine-tune behavior.
043 *
044 * <p>
045 * The following shows a sample object defined in Javascript:
046 * <p class='bjson'>
047 *    {
048 *       id: 1,
049 *       name: <js>'John Smith'</js>,
050 *       uri: <js>'http://sample/addressBook/person/1'</js>,
051 *       addressBookUri: <js>'http://sample/addressBook'</js>,
052 *       birthDate: <js>'1946-08-12T00:00:00Z'</js>,
053 *       otherIds: <jk>null</jk>,
054 *       addresses: [
055 *          {
056 *             uri: <js>'http://sample/addressBook/address/1'</js>,
057 *             personUri: <js>'http://sample/addressBook/person/1'</js>,
058 *             id: 1,
059 *             street: <js>'100 Main Street'</js>,
060 *             city: <js>'Anywhereville'</js>,
061 *             state: <js>'NY'</js>,
062 *             zip: 12345,
063 *             isCurrent: <jk>true</jk>,
064 *          }
065 *       ]
066 *    }
067 * </p>
068 *
069 * <p>
070 * Using the "strict" syntax defined in this document, the equivalent UON notation would be as follows:
071 * <p class='buon'>
072 *    (
073 *       <ua>id</ua>=<un>1</un>,
074 *       <ua>name</ua>=<us>'John+Smith'</us>,
075 *       <ua>uri</ua>=<us>http://sample/addressBook/person/1</us>,
076 *       <ua>addressBookUri</ua>=<us>http://sample/addressBook</us>,
077 *       <ua>birthDate</ua>=<us>1946-08-12T00:00:00Z</us>,
078 *       <ua>otherIds</ua>=<uk>null</uk>,
079 *       <ua>addresses</ua>=@(
080 *          (
081 *             <ua>uri</ua>=<us>http://sample/addressBook/address/1</us>,
082 *             <ua>personUri</ua>=<us>http://sample/addressBook/person/1</us>,
083 *             <ua>id</ua>=<un>1</un>,
084 *             <ua>street</ua>=<us>'100+Main+Street'</us>,
085 *             <ua>city</ua>=<us>Anywhereville</us>,
086 *             <ua>state</ua>=<us>NY</us>,
087 *             <ua>zip</ua>=<un>12345</un>,
088 *             <ua>isCurrent</ua>=<uk>true</uk>
089 *          )
090 *       )
091 *    )
092 * </p>
093 *
094 * <h5 class='section'>Example:</h5>
095 * <p class='bjava'>
096 *    <jc>// Serialize a Map</jc>
097 *    Map <jv>map</jv> = JsonMap.<jsm>ofJson</jsm>(<js>"{a:'b',c:1,d:false,e:['f',1,false],g:{h:'i'}}"</js>);
098 *
099 *    <jc>// Serialize to value equivalent to JSON.</jc>
100 *    <jc>// Produces "(a=b,c=1,d=false,e=@(f,1,false),g=(h=i))"</jc>
101 *    String <jv>uon</jv> = UonSerializer.<jsf>DEFAULT</jsf>.serialize(<jv>map</jv>);
102 *
103 *    <jc>// Serialize a bean</jc>
104 *    <jk>public class</jk> Person {
105 *       <jk>public</jk> Person(String <jv>name</jv>);
106 *       <jk>public</jk> String getName();
107 *       <jk>public int</jk> getAge();
108 *       <jk>public</jk> Address getAddress();
109 *       <jk>public boolean</jk> deceased;
110 *    }
111 *
112 *    <jk>public class</jk> Address {
113 *       <jk>public</jk> String getStreet();
114 *       <jk>public</jk> String getCity();
115 *       <jk>public</jk> String getState();
116 *       <jk>public int</jk> getZip();
117 *    }
118 *
119 *    Person <jv>person</jv> = <jk>new</jk> Person(<js>"John Doe"</js>, 23, <js>"123 Main St"</js>, <js>"Anywhere"</js>,
120 *       <js>"NY"</js>, 12345, <jk>false</jk>);
121 *
122 *    <jc>// Produces "(name='John Doe',age=23,address=(street='123 Main St',city=Anywhere,state=NY,zip=12345),deceased=false)"</jc>
123 *    String <jv>uon</jv> = UonSerializer.<jsf>DEFAULT</jsf>.serialize(<jv>person</jv>);
124 * </p>
125 *
126 * <h5 class='section'>Notes:</h5><ul>
127 *    <li class='note'>This class is thread safe and reusable.
128 * </ul>
129 *
130 * <h5 class='section'>See Also:</h5><ul>
131 *    <li class='link'><a class="doclink" href="../../../../index.html#jm.UonDetails">UON Details</a>
132
133 * </ul>
134 */
135public class UonSerializer extends WriterSerializer implements HttpPartSerializer, UonMetaProvider {
136
137   //-------------------------------------------------------------------------------------------------------------------
138   // Static
139   //-------------------------------------------------------------------------------------------------------------------
140
141   /** Reusable instance of {@link UonSerializer}, all default settings. */
142   public static final UonSerializer DEFAULT = new UonSerializer(create());
143
144   /** Reusable instance of {@link UonSerializer.Readable}. */
145   public static final UonSerializer DEFAULT_READABLE = new Readable(create());
146
147   /** Reusable instance of {@link UonSerializer.Encoding}. */
148   public static final UonSerializer DEFAULT_ENCODING = new Encoding(create());
149
150   /**
151    * Creates a new builder for this object.
152    *
153    * @return A new builder.
154    */
155   public static Builder create() {
156      return new Builder();
157   }
158
159   //-------------------------------------------------------------------------------------------------------------------
160   // Static subclasses
161   //-------------------------------------------------------------------------------------------------------------------
162
163   /**
164    * Equivalent to <code>UonSerializer.<jsm>create</jsm>().ws().build();</code>.
165    */
166   public static class Readable extends UonSerializer {
167
168      /**
169       * Constructor.
170       *
171       * @param builder The builder for this object.
172       */
173      public Readable(Builder builder) {
174         super(builder.useWhitespace());
175      }
176   }
177
178   /**
179    * Equivalent to <code>UonSerializer.<jsm>create</jsm>().encoding().build();</code>.
180    */
181   public static class Encoding extends UonSerializer {
182
183      /**
184       * Constructor.
185       *
186       * @param builder The builder for this object.
187       */
188      public Encoding(Builder builder) {
189         super(builder.encoding());
190      }
191   }
192
193   /**
194    * Converts the specified value to a string that can be used as an HTTP header value, query parameter value,
195    * form-data parameter, or URI path variable.
196    *
197    * <p>
198    * Returned values should NOT be URL-encoded.
199    *
200    * @param partType The category of value being serialized.
201    * @param schema
202    *    Schema information about the part.
203    *    <br>May be <jk>null</jk>.
204    *    <br>Not all part serializers use the schema information.
205    * @param value The value being serialized.
206    * @return The serialized value.
207    * @throws SerializeException If a problem occurred while trying to parse the input.
208    * @throws SchemaValidationException If the output fails schema validation.
209    */
210   public String serialize(HttpPartType partType, HttpPartSchema schema, Object value) throws SchemaValidationException, SerializeException {
211      return getPartSession().serialize(partType, schema, value);
212   }
213
214   //-------------------------------------------------------------------------------------------------------------------
215   // Builder
216   //-------------------------------------------------------------------------------------------------------------------
217
218   /**
219    * Builder class.
220    */
221   @FluentSetters
222   public static class Builder extends WriterSerializer.Builder {
223
224      private static final Cache<HashKey,UonSerializer> CACHE = Cache.of(HashKey.class, UonSerializer.class).build();
225
226      boolean addBeanTypesUon, encoding;
227      ParamFormat paramFormat;
228      Character quoteCharUon;
229
230      /**
231       * Constructor, default settings.
232       */
233      protected Builder() {
234         produces("text/uon");
235         addBeanTypesUon = env("UonSerializer.addBeanTypesUon", false);
236         encoding = env("UonSerializer.encoding", false);
237         paramFormat = env("UonSerializer.paramFormat", ParamFormat.UON);
238         quoteCharUon = null;
239      }
240
241      /**
242       * Copy constructor.
243       *
244       * @param copyFrom The bean to copy from.
245       */
246      protected Builder(UonSerializer copyFrom) {
247         super(copyFrom);
248         addBeanTypesUon = copyFrom.addBeanTypesUon;
249         encoding = copyFrom.encoding;
250         paramFormat = copyFrom.paramFormat;
251         quoteCharUon = copyFrom.quoteCharUon;
252      }
253
254      /**
255       * Copy constructor.
256       *
257       * @param copyFrom The builder to copy from.
258       */
259      protected Builder(Builder copyFrom) {
260         super(copyFrom);
261         addBeanTypesUon = copyFrom.addBeanTypesUon;
262         encoding = copyFrom.encoding;
263         paramFormat = copyFrom.paramFormat;
264         quoteCharUon = copyFrom.quoteCharUon;
265      }
266
267      @Override /* Context.Builder */
268      public Builder copy() {
269         return new Builder(this);
270      }
271
272      @Override /* Context.Builder */
273      public UonSerializer build() {
274         return cache(CACHE).build(UonSerializer.class);
275      }
276
277      @Override /* Context.Builder */
278      public HashKey hashKey() {
279         return HashKey.of(
280            super.hashKey(),
281            addBeanTypesUon,
282            encoding,
283            paramFormat,
284            quoteCharUon
285         );
286      }
287
288      //-----------------------------------------------------------------------------------------------------------------
289      // Properties
290      //-----------------------------------------------------------------------------------------------------------------
291
292      /**
293       * Add <js>"_type"</js> properties when needed.
294       *
295       * <p>
296       * If <jk>true</jk>, then <js>"_type"</js> properties will be added to beans if their type cannot be inferred
297       * through reflection.
298       *
299       * <p>
300       * When present, this value overrides the {@link org.apache.juneau.serializer.Serializer.Builder#addBeanTypes()} setting and is
301       * provided to customize the behavior of specific serializers in a {@link SerializerSet}.
302       *
303       * @return This object.
304       */
305      @FluentSetter
306      public Builder addBeanTypesUon() {
307         return addBeanTypesUon(true);
308      }
309
310      /**
311       * Same as {@link #addBeanTypesUon()} but allows you to explicitly specify the value.
312       *
313       * @param value The value for this setting.
314       * @return This object.
315       */
316      @FluentSetter
317      public Builder addBeanTypesUon(boolean value) {
318         addBeanTypesUon = value;
319         return this;
320      }
321
322      /**
323       * Encode non-valid URI characters.
324       *
325       * <p>
326       * Encode non-valid URI characters with <js>"%xx"</js> constructs.
327       *
328       * <p>
329       * If <jk>true</jk>, non-valid URI characters will be converted to <js>"%xx"</js> sequences.
330       * <br>Set to <jk>false</jk> if parameter value is being passed to some other code that will already perform
331       * URL-encoding of non-valid URI characters.
332       *
333       * <h5 class='section'>Example:</h5>
334       * <p class='bjava'>
335       *    <jc>// Create a non-encoding UON serializer.</jc>
336       *    UonSerializer <jv>serializer1</jv> = UonSerializer.
337       *       .<jsm>create</jsm>()
338       *       .build();
339       *
340       *    <jc>// Create an encoding UON serializer.</jc>
341       *    UonSerializer <jv>serializer2</jv> = UonSerializer.
342       *       .<jsm>create</jsm>()
343       *       .encoding()
344       *       .build();
345       *
346       *    JsonMap <jv>map</jv> = JsonMap.<jsm>of</jsm>(<js>"foo"</js>, <js>"foo bar"</js>);
347       *
348       *    <jc>// Produces: "(foo=foo bar)"</jc>
349       *    String <jv>uon1</jv> = <jv>serializer1</jv>.serialize(<jv>map</jv>)
350       *
351       *    <jc>// Produces: "(foo=foo%20bar)"</jc>
352       *    String <jv>uon2</jv> = <jv>serializer2</jv>.serialize(<jv>map</jv>)
353       * </p>
354       *
355       * @return This object.
356       */
357      @FluentSetter
358      public Builder encoding() {
359         return encoding(true);
360      }
361
362      /**
363       * Same as {@link #encoding()} but allows you to disable the previous setting.
364       *
365       * @param value The new value for this setting.
366       * @return This object.
367       */
368      public Builder encoding(boolean value) {
369         encoding = value;
370         return this;
371      }
372
373      /**
374       * Format to use for query/form-data/header values.
375       *
376       * <p>
377       * Specifies the format to use for URL GET parameter keys and values.
378       *
379       * <h5 class='section'>Example:</h5>
380       * <p class='bjava'>
381       *    <jc>// Create a normal UON serializer.</jc>
382       *    UonSerializer <jv>serializer1</jv> = UonSerializer
383       *       .<jsm>create</jsm>()
384       *       .build();
385       *
386       *    <jc>// Create a plain-text UON serializer.</jc>
387       *    UonSerializer <jv>serializer2</jv> = UonSerializer
388       *       .<jsm>create</jsm>()
389       *       .paramFormat(<jsf>PLAIN_TEXT</jsf>)
390       *       .build();
391       *
392       *    JsonMap <jv>map</jv> = JsonMap.<jsm>of</jsm>(
393       *       <js>"foo"</js>, <js>"bar"</js>,
394       *       <js>"baz"</js>, <jk>new</jk> String[]{<js>"qux"</js>, <js>"true"</js>, <js>"123"</js>}
395       *    );
396       *
397       *    <jc>// Produces: "(foo=bar,baz=@(qux,'true','123'))"</jc>
398       *    String <jv>uon1</jv> = <jv>serializer1</jv>.serialize(<jv>map</jv>)
399       *
400       *    <jc>// Produces: "foo=bar,baz=qux,true,123"</jc>
401       *    String <jv>uon2</jv> = <jv>serializer2</jv>.serialize(<jv>map</jv>)
402       * </p>
403       *
404       * <p>
405       * <ul class='values javatree'>
406       *    <li class='jf'>{@link ParamFormat#UON} (default) - Use UON notation for parameters.
407       *    <li class='jf'>{@link ParamFormat#PLAINTEXT} - Use plain text for parameters.
408       * </ul>
409       *
410       * @param value
411       *    The new value for this property.
412       *    <br>The default value is {@link ParamFormat#UON}.
413       * @return This object.
414       */
415      @FluentSetter
416      public Builder paramFormat(ParamFormat value) {
417         paramFormat = value;
418         return this;
419      }
420
421      /**
422       * Format to use for query/form-data/header values.
423       *
424       * <p>
425       * Specifies plain-text for the format to use for URL GET parameter keys and values.
426       *
427       * <h5 class='section'>Example:</h5>
428       * <p class='bjava'>
429       *    <jc>// Create a plain-text UON serializer.</jc>
430       *    UonSerializer <jv>serializer</jv> = UonSerializer
431       *       .<jsm>create</jsm>()
432       *       .paramFormatPlain()
433       *       .build();
434       *
435       *    JsonMap <jv>map</jv> = JsonMap.<jsm>of</jsm>(
436       *       <js>"foo"</js>, <js>"bar"</js>,
437       *       <js>"baz"</js>, <jk>new</jk> String[]{<js>"qux"</js>, <js>"true"</js>, <js>"123"</js>}
438       *    );
439       *
440       *    <jc>// Produces: "foo=bar,baz=qux,true,123"</jc>
441       *    String <jv>uon</jv> = <jv>serializer</jv>.serialize(<jv>map</jv>)
442       * </p>
443       *
444       * @return This object.
445       */
446      @FluentSetter
447      public Builder paramFormatPlain() {
448         return paramFormat(ParamFormat.PLAINTEXT);
449      }
450
451      /**
452       * Specifies the quote character.
453       *
454       * @param value The value for this setting.
455       * @return This object.
456       */
457      @FluentSetter
458      public Builder quoteCharUon(char value) {
459         quoteCharUon = value;
460         return this;
461      }
462
463      // <FluentSetters>
464
465      @Override /* GENERATED - org.apache.juneau.Context.Builder */
466      public Builder annotations(Annotation...values) {
467         super.annotations(values);
468         return this;
469      }
470
471      @Override /* GENERATED - org.apache.juneau.Context.Builder */
472      public Builder apply(AnnotationWorkList work) {
473         super.apply(work);
474         return this;
475      }
476
477      @Override /* GENERATED - org.apache.juneau.Context.Builder */
478      public Builder applyAnnotations(java.lang.Class<?>...fromClasses) {
479         super.applyAnnotations(fromClasses);
480         return this;
481      }
482
483      @Override /* GENERATED - org.apache.juneau.Context.Builder */
484      public Builder applyAnnotations(Method...fromMethods) {
485         super.applyAnnotations(fromMethods);
486         return this;
487      }
488
489      @Override /* GENERATED - org.apache.juneau.Context.Builder */
490      public Builder cache(Cache<HashKey,? extends org.apache.juneau.Context> value) {
491         super.cache(value);
492         return this;
493      }
494
495      @Override /* GENERATED - org.apache.juneau.Context.Builder */
496      public Builder debug() {
497         super.debug();
498         return this;
499      }
500
501      @Override /* GENERATED - org.apache.juneau.Context.Builder */
502      public Builder debug(boolean value) {
503         super.debug(value);
504         return this;
505      }
506
507      @Override /* GENERATED - org.apache.juneau.Context.Builder */
508      public Builder impl(Context value) {
509         super.impl(value);
510         return this;
511      }
512
513      @Override /* GENERATED - org.apache.juneau.Context.Builder */
514      public Builder type(Class<? extends org.apache.juneau.Context> value) {
515         super.type(value);
516         return this;
517      }
518
519      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
520      public Builder beanClassVisibility(Visibility value) {
521         super.beanClassVisibility(value);
522         return this;
523      }
524
525      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
526      public Builder beanConstructorVisibility(Visibility value) {
527         super.beanConstructorVisibility(value);
528         return this;
529      }
530
531      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
532      public Builder beanContext(BeanContext value) {
533         super.beanContext(value);
534         return this;
535      }
536
537      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
538      public Builder beanContext(BeanContext.Builder value) {
539         super.beanContext(value);
540         return this;
541      }
542
543      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
544      public Builder beanDictionary(java.lang.Class<?>...values) {
545         super.beanDictionary(values);
546         return this;
547      }
548
549      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
550      public Builder beanFieldVisibility(Visibility value) {
551         super.beanFieldVisibility(value);
552         return this;
553      }
554
555      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
556      public Builder beanInterceptor(Class<?> on, Class<? extends org.apache.juneau.swap.BeanInterceptor<?>> value) {
557         super.beanInterceptor(on, value);
558         return this;
559      }
560
561      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
562      public Builder beanMapPutReturnsOldValue() {
563         super.beanMapPutReturnsOldValue();
564         return this;
565      }
566
567      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
568      public Builder beanMethodVisibility(Visibility value) {
569         super.beanMethodVisibility(value);
570         return this;
571      }
572
573      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
574      public Builder beanProperties(Map<String,Object> values) {
575         super.beanProperties(values);
576         return this;
577      }
578
579      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
580      public Builder beanProperties(Class<?> beanClass, String properties) {
581         super.beanProperties(beanClass, properties);
582         return this;
583      }
584
585      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
586      public Builder beanProperties(String beanClassName, String properties) {
587         super.beanProperties(beanClassName, properties);
588         return this;
589      }
590
591      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
592      public Builder beanPropertiesExcludes(Map<String,Object> values) {
593         super.beanPropertiesExcludes(values);
594         return this;
595      }
596
597      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
598      public Builder beanPropertiesExcludes(Class<?> beanClass, String properties) {
599         super.beanPropertiesExcludes(beanClass, properties);
600         return this;
601      }
602
603      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
604      public Builder beanPropertiesExcludes(String beanClassName, String properties) {
605         super.beanPropertiesExcludes(beanClassName, properties);
606         return this;
607      }
608
609      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
610      public Builder beanPropertiesReadOnly(Map<String,Object> values) {
611         super.beanPropertiesReadOnly(values);
612         return this;
613      }
614
615      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
616      public Builder beanPropertiesReadOnly(Class<?> beanClass, String properties) {
617         super.beanPropertiesReadOnly(beanClass, properties);
618         return this;
619      }
620
621      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
622      public Builder beanPropertiesReadOnly(String beanClassName, String properties) {
623         super.beanPropertiesReadOnly(beanClassName, properties);
624         return this;
625      }
626
627      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
628      public Builder beanPropertiesWriteOnly(Map<String,Object> values) {
629         super.beanPropertiesWriteOnly(values);
630         return this;
631      }
632
633      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
634      public Builder beanPropertiesWriteOnly(Class<?> beanClass, String properties) {
635         super.beanPropertiesWriteOnly(beanClass, properties);
636         return this;
637      }
638
639      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
640      public Builder beanPropertiesWriteOnly(String beanClassName, String properties) {
641         super.beanPropertiesWriteOnly(beanClassName, properties);
642         return this;
643      }
644
645      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
646      public Builder beansRequireDefaultConstructor() {
647         super.beansRequireDefaultConstructor();
648         return this;
649      }
650
651      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
652      public Builder beansRequireSerializable() {
653         super.beansRequireSerializable();
654         return this;
655      }
656
657      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
658      public Builder beansRequireSettersForGetters() {
659         super.beansRequireSettersForGetters();
660         return this;
661      }
662
663      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
664      public Builder dictionaryOn(Class<?> on, java.lang.Class<?>...values) {
665         super.dictionaryOn(on, values);
666         return this;
667      }
668
669      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
670      public Builder disableBeansRequireSomeProperties() {
671         super.disableBeansRequireSomeProperties();
672         return this;
673      }
674
675      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
676      public Builder disableIgnoreMissingSetters() {
677         super.disableIgnoreMissingSetters();
678         return this;
679      }
680
681      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
682      public Builder disableIgnoreTransientFields() {
683         super.disableIgnoreTransientFields();
684         return this;
685      }
686
687      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
688      public Builder disableIgnoreUnknownNullBeanProperties() {
689         super.disableIgnoreUnknownNullBeanProperties();
690         return this;
691      }
692
693      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
694      public Builder disableInterfaceProxies() {
695         super.disableInterfaceProxies();
696         return this;
697      }
698
699      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
700      public <T> Builder example(Class<T> pojoClass, T o) {
701         super.example(pojoClass, o);
702         return this;
703      }
704
705      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
706      public <T> Builder example(Class<T> pojoClass, String json) {
707         super.example(pojoClass, json);
708         return this;
709      }
710
711      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
712      public Builder findFluentSetters() {
713         super.findFluentSetters();
714         return this;
715      }
716
717      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
718      public Builder findFluentSetters(Class<?> on) {
719         super.findFluentSetters(on);
720         return this;
721      }
722
723      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
724      public Builder ignoreInvocationExceptionsOnGetters() {
725         super.ignoreInvocationExceptionsOnGetters();
726         return this;
727      }
728
729      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
730      public Builder ignoreInvocationExceptionsOnSetters() {
731         super.ignoreInvocationExceptionsOnSetters();
732         return this;
733      }
734
735      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
736      public Builder ignoreUnknownBeanProperties() {
737         super.ignoreUnknownBeanProperties();
738         return this;
739      }
740
741      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
742      public Builder ignoreUnknownEnumValues() {
743         super.ignoreUnknownEnumValues();
744         return this;
745      }
746
747      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
748      public Builder implClass(Class<?> interfaceClass, Class<?> implClass) {
749         super.implClass(interfaceClass, implClass);
750         return this;
751      }
752
753      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
754      public Builder implClasses(Map<Class<?>,Class<?>> values) {
755         super.implClasses(values);
756         return this;
757      }
758
759      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
760      public Builder interfaceClass(Class<?> on, Class<?> value) {
761         super.interfaceClass(on, value);
762         return this;
763      }
764
765      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
766      public Builder interfaces(java.lang.Class<?>...value) {
767         super.interfaces(value);
768         return this;
769      }
770
771      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
772      public Builder locale(Locale value) {
773         super.locale(value);
774         return this;
775      }
776
777      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
778      public Builder mediaType(MediaType value) {
779         super.mediaType(value);
780         return this;
781      }
782
783      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
784      public Builder notBeanClasses(java.lang.Class<?>...values) {
785         super.notBeanClasses(values);
786         return this;
787      }
788
789      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
790      public Builder notBeanPackages(String...values) {
791         super.notBeanPackages(values);
792         return this;
793      }
794
795      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
796      public Builder propertyNamer(Class<? extends org.apache.juneau.PropertyNamer> value) {
797         super.propertyNamer(value);
798         return this;
799      }
800
801      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
802      public Builder propertyNamer(Class<?> on, Class<? extends org.apache.juneau.PropertyNamer> value) {
803         super.propertyNamer(on, value);
804         return this;
805      }
806
807      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
808      public Builder sortProperties() {
809         super.sortProperties();
810         return this;
811      }
812
813      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
814      public Builder sortProperties(java.lang.Class<?>...on) {
815         super.sortProperties(on);
816         return this;
817      }
818
819      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
820      public Builder stopClass(Class<?> on, Class<?> value) {
821         super.stopClass(on, value);
822         return this;
823      }
824
825      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
826      public <T, S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction) {
827         super.swap(normalClass, swappedClass, swapFunction);
828         return this;
829      }
830
831      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
832      public <T, S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction, ThrowingFunction<S,T> unswapFunction) {
833         super.swap(normalClass, swappedClass, swapFunction, unswapFunction);
834         return this;
835      }
836
837      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
838      public Builder swaps(java.lang.Class<?>...values) {
839         super.swaps(values);
840         return this;
841      }
842
843      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
844      public Builder timeZone(TimeZone value) {
845         super.timeZone(value);
846         return this;
847      }
848
849      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
850      public Builder typeName(Class<?> on, String value) {
851         super.typeName(on, value);
852         return this;
853      }
854
855      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
856      public Builder typePropertyName(String value) {
857         super.typePropertyName(value);
858         return this;
859      }
860
861      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
862      public Builder typePropertyName(Class<?> on, String value) {
863         super.typePropertyName(on, value);
864         return this;
865      }
866
867      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
868      public Builder useEnumNames() {
869         super.useEnumNames();
870         return this;
871      }
872
873      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
874      public Builder useJavaBeanIntrospector() {
875         super.useJavaBeanIntrospector();
876         return this;
877      }
878
879      @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */
880      public Builder detectRecursions() {
881         super.detectRecursions();
882         return this;
883      }
884
885      @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */
886      public Builder detectRecursions(boolean value) {
887         super.detectRecursions(value);
888         return this;
889      }
890
891      @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */
892      public Builder ignoreRecursions() {
893         super.ignoreRecursions();
894         return this;
895      }
896
897      @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */
898      public Builder ignoreRecursions(boolean value) {
899         super.ignoreRecursions(value);
900         return this;
901      }
902
903      @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */
904      public Builder initialDepth(int value) {
905         super.initialDepth(value);
906         return this;
907      }
908
909      @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */
910      public Builder maxDepth(int value) {
911         super.maxDepth(value);
912         return this;
913      }
914
915      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
916      public Builder accept(String value) {
917         super.accept(value);
918         return this;
919      }
920
921      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
922      public Builder addBeanTypes() {
923         super.addBeanTypes();
924         return this;
925      }
926
927      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
928      public Builder addBeanTypes(boolean value) {
929         super.addBeanTypes(value);
930         return this;
931      }
932
933      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
934      public Builder addRootType() {
935         super.addRootType();
936         return this;
937      }
938
939      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
940      public Builder addRootType(boolean value) {
941         super.addRootType(value);
942         return this;
943      }
944
945      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
946      public Builder keepNullProperties() {
947         super.keepNullProperties();
948         return this;
949      }
950
951      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
952      public Builder keepNullProperties(boolean value) {
953         super.keepNullProperties(value);
954         return this;
955      }
956
957      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
958      public Builder listener(Class<? extends org.apache.juneau.serializer.SerializerListener> value) {
959         super.listener(value);
960         return this;
961      }
962
963      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
964      public Builder produces(String value) {
965         super.produces(value);
966         return this;
967      }
968
969      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
970      public Builder sortCollections() {
971         super.sortCollections();
972         return this;
973      }
974
975      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
976      public Builder sortCollections(boolean value) {
977         super.sortCollections(value);
978         return this;
979      }
980
981      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
982      public Builder sortMaps() {
983         super.sortMaps();
984         return this;
985      }
986
987      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
988      public Builder sortMaps(boolean value) {
989         super.sortMaps(value);
990         return this;
991      }
992
993      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
994      public Builder trimEmptyCollections() {
995         super.trimEmptyCollections();
996         return this;
997      }
998
999      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1000      public Builder trimEmptyCollections(boolean value) {
1001         super.trimEmptyCollections(value);
1002         return this;
1003      }
1004
1005      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1006      public Builder trimEmptyMaps() {
1007         super.trimEmptyMaps();
1008         return this;
1009      }
1010
1011      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1012      public Builder trimEmptyMaps(boolean value) {
1013         super.trimEmptyMaps(value);
1014         return this;
1015      }
1016
1017      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1018      public Builder trimStrings() {
1019         super.trimStrings();
1020         return this;
1021      }
1022
1023      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1024      public Builder trimStrings(boolean value) {
1025         super.trimStrings(value);
1026         return this;
1027      }
1028
1029      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1030      public Builder uriContext(UriContext value) {
1031         super.uriContext(value);
1032         return this;
1033      }
1034
1035      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1036      public Builder uriRelativity(UriRelativity value) {
1037         super.uriRelativity(value);
1038         return this;
1039      }
1040
1041      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1042      public Builder uriResolution(UriResolution value) {
1043         super.uriResolution(value);
1044         return this;
1045      }
1046
1047      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1048      public Builder fileCharset(Charset value) {
1049         super.fileCharset(value);
1050         return this;
1051      }
1052
1053      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1054      public Builder maxIndent(int value) {
1055         super.maxIndent(value);
1056         return this;
1057      }
1058
1059      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1060      public Builder quoteChar(char value) {
1061         super.quoteChar(value);
1062         return this;
1063      }
1064
1065      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1066      public Builder quoteCharOverride(char value) {
1067         super.quoteCharOverride(value);
1068         return this;
1069      }
1070
1071      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1072      public Builder sq() {
1073         super.sq();
1074         return this;
1075      }
1076
1077      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1078      public Builder streamCharset(Charset value) {
1079         super.streamCharset(value);
1080         return this;
1081      }
1082
1083      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1084      public Builder useWhitespace() {
1085         super.useWhitespace();
1086         return this;
1087      }
1088
1089      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1090      public Builder useWhitespace(boolean value) {
1091         super.useWhitespace(value);
1092         return this;
1093      }
1094
1095      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1096      public Builder ws() {
1097         super.ws();
1098         return this;
1099      }
1100
1101      // </FluentSetters>
1102   }
1103
1104   //-------------------------------------------------------------------------------------------------------------------
1105   // Instance
1106   //-------------------------------------------------------------------------------------------------------------------
1107
1108   final boolean
1109      encoding,
1110      addBeanTypesUon;
1111   final ParamFormat
1112      paramFormat;
1113   final Character
1114      quoteCharUon;
1115
1116   private final boolean addBeanTypes;
1117   private final char quoteChar;
1118
1119   private final Map<ClassMeta<?>,UonClassMeta> uonClassMetas = new ConcurrentHashMap<>();
1120   private final Map<BeanPropertyMeta,UonBeanPropertyMeta> uonBeanPropertyMetas = new ConcurrentHashMap<>();
1121
1122   /**
1123    * Constructor.
1124    *
1125    * @param builder
1126    *    The builder for this object.
1127    */
1128   public UonSerializer(Builder builder) {
1129      super(builder);
1130
1131      encoding = builder.encoding;
1132      addBeanTypesUon = builder.addBeanTypesUon;
1133      paramFormat = builder.paramFormat;
1134      quoteCharUon = builder.quoteCharUon;
1135
1136      addBeanTypes = addBeanTypesUon || super.isAddBeanTypes();
1137      quoteChar = quoteCharUon != null ? quoteCharUon : super.quoteChar() != null ? super.quoteChar() : '\'';
1138   }
1139
1140   @Override /* Context */
1141   public Builder copy() {
1142      return new Builder(this);
1143   }
1144
1145   @Override /* Context */
1146   public  UonSerializerSession.Builder createSession() {
1147      return UonSerializerSession.create(this);
1148   }
1149
1150   @Override /* Context */
1151   public UonSerializerSession getSession() {
1152      return createSession().build();
1153   }
1154
1155   @Override /* HttpPartSerializer */
1156   public UonSerializerSession getPartSession() {
1157      return UonSerializerSession.create(this).build();
1158   }
1159
1160   //-----------------------------------------------------------------------------------------------------------------
1161   // Extended metadata
1162   //-----------------------------------------------------------------------------------------------------------------
1163
1164   @Override /* UonMetaProvider */
1165   public UonClassMeta getUonClassMeta(ClassMeta<?> cm) {
1166      UonClassMeta m = uonClassMetas.get(cm);
1167      if (m == null) {
1168         m = new UonClassMeta(cm, this);
1169         uonClassMetas.put(cm, m);
1170      }
1171      return m;
1172   }
1173
1174   @Override /* UonMetaProvider */
1175   public UonBeanPropertyMeta getUonBeanPropertyMeta(BeanPropertyMeta bpm) {
1176      if (bpm == null)
1177         return UonBeanPropertyMeta.DEFAULT;
1178      UonBeanPropertyMeta m = uonBeanPropertyMetas.get(bpm);
1179      if (m == null) {
1180         m = new UonBeanPropertyMeta(bpm.getDelegateFor(), this);
1181         uonBeanPropertyMetas.put(bpm, m);
1182      }
1183      return m;
1184   }
1185
1186   //-----------------------------------------------------------------------------------------------------------------
1187   // Properties
1188   //-----------------------------------------------------------------------------------------------------------------
1189
1190   /**
1191    * Add <js>"_type"</js> properties when needed.
1192    *
1193    * @see Builder#addBeanTypesUon()
1194    * @return
1195    *    <jk>true</jk> if <js>"_type"</js> properties will be added to beans if their type cannot be inferred
1196    *    through reflection.
1197    */
1198   @Override
1199   protected final boolean isAddBeanTypes() {
1200      return addBeanTypes;
1201   }
1202
1203   /**
1204    * Encode non-valid URI characters.
1205    *
1206    * @see Builder#encoding()
1207    * @return
1208    *    <jk>true</jk> if non-valid URI characters should be encoded with <js>"%xx"</js> constructs.
1209    */
1210   protected final boolean isEncoding() {
1211      return encoding;
1212   }
1213
1214   /**
1215    * Format to use for query/form-data/header values.
1216    *
1217    * @see Builder#paramFormat(ParamFormat)
1218    * @return
1219    *    Specifies the format to use for URL GET parameter keys and values.
1220    */
1221   protected final ParamFormat getParamFormat() {
1222      return paramFormat;
1223   }
1224
1225   /**
1226    * Quote character.
1227    *
1228    * @see Builder#quoteCharUon(char)
1229    * @return
1230    *    The character used for quoting attributes and values.
1231    */
1232   @Override
1233   protected final char getQuoteChar() {
1234      return quoteChar;
1235   }
1236
1237   //-----------------------------------------------------------------------------------------------------------------
1238   // Other methods
1239   //-----------------------------------------------------------------------------------------------------------------
1240
1241   @Override /* Context */
1242   protected JsonMap properties() {
1243      return filteredMap("encoding", encoding, "addBeanTypes", addBeanTypes, "paramFormat", paramFormat);
1244   }
1245}