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         super();
235         produces("text/uon");
236         addBeanTypesUon = env("UonSerializer.addBeanTypesUon", false);
237         encoding = env("UonSerializer.encoding", false);
238         paramFormat = env("UonSerializer.paramFormat", ParamFormat.UON);
239         quoteCharUon = null;
240      }
241
242      /**
243       * Copy constructor.
244       *
245       * @param copyFrom The bean to copy from.
246       */
247      protected Builder(UonSerializer copyFrom) {
248         super(copyFrom);
249         addBeanTypesUon = copyFrom.addBeanTypesUon;
250         encoding = copyFrom.encoding;
251         paramFormat = copyFrom.paramFormat;
252         quoteCharUon = copyFrom.quoteCharUon;
253      }
254
255      /**
256       * Copy constructor.
257       *
258       * @param copyFrom The builder to copy from.
259       */
260      protected Builder(Builder copyFrom) {
261         super(copyFrom);
262         addBeanTypesUon = copyFrom.addBeanTypesUon;
263         encoding = copyFrom.encoding;
264         paramFormat = copyFrom.paramFormat;
265         quoteCharUon = copyFrom.quoteCharUon;
266      }
267
268      @Override /* Context.Builder */
269      public Builder copy() {
270         return new Builder(this);
271      }
272
273      @Override /* Context.Builder */
274      public UonSerializer build() {
275         return cache(CACHE).build(UonSerializer.class);
276      }
277
278      @Override /* Context.Builder */
279      public HashKey hashKey() {
280         return HashKey.of(
281            super.hashKey(),
282            addBeanTypesUon,
283            encoding,
284            paramFormat,
285            quoteCharUon
286         );
287      }
288
289      //-----------------------------------------------------------------------------------------------------------------
290      // Properties
291      //-----------------------------------------------------------------------------------------------------------------
292
293      /**
294       * Add <js>"_type"</js> properties when needed.
295       *
296       * <p>
297       * If <jk>true</jk>, then <js>"_type"</js> properties will be added to beans if their type cannot be inferred
298       * through reflection.
299       *
300       * <p>
301       * When present, this value overrides the {@link org.apache.juneau.serializer.Serializer.Builder#addBeanTypes()} setting and is
302       * provided to customize the behavior of specific serializers in a {@link SerializerSet}.
303       *
304       * @return This object.
305       */
306      @FluentSetter
307      public Builder addBeanTypesUon() {
308         return addBeanTypesUon(true);
309      }
310
311      /**
312       * Same as {@link #addBeanTypesUon()} but allows you to explicitly specify the value.
313       *
314       * @param value The value for this setting.
315       * @return This object.
316       */
317      @FluentSetter
318      public Builder addBeanTypesUon(boolean value) {
319         addBeanTypesUon = value;
320         return this;
321      }
322
323      /**
324       * Encode non-valid URI characters.
325       *
326       * <p>
327       * Encode non-valid URI characters with <js>"%xx"</js> constructs.
328       *
329       * <p>
330       * If <jk>true</jk>, non-valid URI characters will be converted to <js>"%xx"</js> sequences.
331       * <br>Set to <jk>false</jk> if parameter value is being passed to some other code that will already perform
332       * URL-encoding of non-valid URI characters.
333       *
334       * <h5 class='section'>Example:</h5>
335       * <p class='bjava'>
336       *    <jc>// Create a non-encoding UON serializer.</jc>
337       *    UonSerializer <jv>serializer1</jv> = UonSerializer.
338       *       .<jsm>create</jsm>()
339       *       .build();
340       *
341       *    <jc>// Create an encoding UON serializer.</jc>
342       *    UonSerializer <jv>serializer2</jv> = UonSerializer.
343       *       .<jsm>create</jsm>()
344       *       .encoding()
345       *       .build();
346       *
347       *    JsonMap <jv>map</jv> = JsonMap.<jsm>of</jsm>(<js>"foo"</js>, <js>"foo bar"</js>);
348       *
349       *    <jc>// Produces: "(foo=foo bar)"</jc>
350       *    String <jv>uon1</jv> = <jv>serializer1</jv>.serialize(<jv>map</jv>)
351       *
352       *    <jc>// Produces: "(foo=foo%20bar)"</jc>
353       *    String <jv>uon2</jv> = <jv>serializer2</jv>.serialize(<jv>map</jv>)
354       * </p>
355       *
356       * @return This object.
357       */
358      @FluentSetter
359      public Builder encoding() {
360         return encoding(true);
361      }
362
363      /**
364       * Same as {@link #encoding()} but allows you to disable the previous setting.
365       *
366       * @param value The new value for this setting.
367       * @return This object.
368       */
369      public Builder encoding(boolean value) {
370         encoding = value;
371         return this;
372      }
373
374      /**
375       * Format to use for query/form-data/header values.
376       *
377       * <p>
378       * Specifies the format to use for URL GET parameter keys and values.
379       *
380       * <h5 class='section'>Example:</h5>
381       * <p class='bjava'>
382       *    <jc>// Create a normal UON serializer.</jc>
383       *    UonSerializer <jv>serializer1</jv> = UonSerializer
384       *       .<jsm>create</jsm>()
385       *       .build();
386       *
387       *    <jc>// Create a plain-text UON serializer.</jc>
388       *    UonSerializer <jv>serializer2</jv> = UonSerializer
389       *       .<jsm>create</jsm>()
390       *       .paramFormat(<jsf>PLAIN_TEXT</jsf>)
391       *       .build();
392       *
393       *    JsonMap <jv>map</jv> = JsonMap.<jsm>of</jsm>(
394       *       <js>"foo"</js>, <js>"bar"</js>,
395       *       <js>"baz"</js>, <jk>new</jk> String[]{<js>"qux"</js>, <js>"true"</js>, <js>"123"</js>}
396       *    );
397       *
398       *    <jc>// Produces: "(foo=bar,baz=@(qux,'true','123'))"</jc>
399       *    String <jv>uon1</jv> = <jv>serializer1</jv>.serialize(<jv>map</jv>)
400       *
401       *    <jc>// Produces: "foo=bar,baz=qux,true,123"</jc>
402       *    String <jv>uon2</jv> = <jv>serializer2</jv>.serialize(<jv>map</jv>)
403       * </p>
404       *
405       * <p>
406       * <ul class='values javatree'>
407       *    <li class='jf'>{@link ParamFormat#UON} (default) - Use UON notation for parameters.
408       *    <li class='jf'>{@link ParamFormat#PLAINTEXT} - Use plain text for parameters.
409       * </ul>
410       *
411       * @param value
412       *    The new value for this property.
413       *    <br>The default value is {@link ParamFormat#UON}.
414       * @return This object.
415       */
416      @FluentSetter
417      public Builder paramFormat(ParamFormat value) {
418         paramFormat = value;
419         return this;
420      }
421
422      /**
423       * Format to use for query/form-data/header values.
424       *
425       * <p>
426       * Specifies plain-text for the format to use for URL GET parameter keys and values.
427       *
428       * <h5 class='section'>Example:</h5>
429       * <p class='bjava'>
430       *    <jc>// Create a plain-text UON serializer.</jc>
431       *    UonSerializer <jv>serializer</jv> = UonSerializer
432       *       .<jsm>create</jsm>()
433       *       .paramFormatPlain()
434       *       .build();
435       *
436       *    JsonMap <jv>map</jv> = JsonMap.<jsm>of</jsm>(
437       *       <js>"foo"</js>, <js>"bar"</js>,
438       *       <js>"baz"</js>, <jk>new</jk> String[]{<js>"qux"</js>, <js>"true"</js>, <js>"123"</js>}
439       *    );
440       *
441       *    <jc>// Produces: "foo=bar,baz=qux,true,123"</jc>
442       *    String <jv>uon</jv> = <jv>serializer</jv>.serialize(<jv>map</jv>)
443       * </p>
444       *
445       * @return This object.
446       */
447      @FluentSetter
448      public Builder paramFormatPlain() {
449         return paramFormat(ParamFormat.PLAINTEXT);
450      }
451
452      /**
453       * Specifies the quote character.
454       *
455       * @param value The value for this setting.
456       * @return This object.
457       */
458      @FluentSetter
459      public Builder quoteCharUon(char value) {
460         quoteCharUon = value;
461         return this;
462      }
463
464      // <FluentSetters>
465
466      @Override /* GENERATED - org.apache.juneau.Context.Builder */
467      public Builder annotations(Annotation...values) {
468         super.annotations(values);
469         return this;
470      }
471
472      @Override /* GENERATED - org.apache.juneau.Context.Builder */
473      public Builder apply(AnnotationWorkList work) {
474         super.apply(work);
475         return this;
476      }
477
478      @Override /* GENERATED - org.apache.juneau.Context.Builder */
479      public Builder applyAnnotations(java.lang.Class<?>...fromClasses) {
480         super.applyAnnotations(fromClasses);
481         return this;
482      }
483
484      @Override /* GENERATED - org.apache.juneau.Context.Builder */
485      public Builder applyAnnotations(Method...fromMethods) {
486         super.applyAnnotations(fromMethods);
487         return this;
488      }
489
490      @Override /* GENERATED - org.apache.juneau.Context.Builder */
491      public Builder cache(Cache<HashKey,? extends org.apache.juneau.Context> value) {
492         super.cache(value);
493         return this;
494      }
495
496      @Override /* GENERATED - org.apache.juneau.Context.Builder */
497      public Builder debug() {
498         super.debug();
499         return this;
500      }
501
502      @Override /* GENERATED - org.apache.juneau.Context.Builder */
503      public Builder debug(boolean value) {
504         super.debug(value);
505         return this;
506      }
507
508      @Override /* GENERATED - org.apache.juneau.Context.Builder */
509      public Builder impl(Context value) {
510         super.impl(value);
511         return this;
512      }
513
514      @Override /* GENERATED - org.apache.juneau.Context.Builder */
515      public Builder type(Class<? extends org.apache.juneau.Context> value) {
516         super.type(value);
517         return this;
518      }
519
520      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
521      public Builder beanClassVisibility(Visibility value) {
522         super.beanClassVisibility(value);
523         return this;
524      }
525
526      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
527      public Builder beanConstructorVisibility(Visibility value) {
528         super.beanConstructorVisibility(value);
529         return this;
530      }
531
532      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
533      public Builder beanContext(BeanContext value) {
534         super.beanContext(value);
535         return this;
536      }
537
538      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
539      public Builder beanContext(BeanContext.Builder value) {
540         super.beanContext(value);
541         return this;
542      }
543
544      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
545      public Builder beanDictionary(java.lang.Class<?>...values) {
546         super.beanDictionary(values);
547         return this;
548      }
549
550      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
551      public Builder beanFieldVisibility(Visibility value) {
552         super.beanFieldVisibility(value);
553         return this;
554      }
555
556      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
557      public Builder beanInterceptor(Class<?> on, Class<? extends org.apache.juneau.swap.BeanInterceptor<?>> value) {
558         super.beanInterceptor(on, value);
559         return this;
560      }
561
562      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
563      public Builder beanMapPutReturnsOldValue() {
564         super.beanMapPutReturnsOldValue();
565         return this;
566      }
567
568      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
569      public Builder beanMethodVisibility(Visibility value) {
570         super.beanMethodVisibility(value);
571         return this;
572      }
573
574      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
575      public Builder beanProperties(Map<String,Object> values) {
576         super.beanProperties(values);
577         return this;
578      }
579
580      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
581      public Builder beanProperties(Class<?> beanClass, String properties) {
582         super.beanProperties(beanClass, properties);
583         return this;
584      }
585
586      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
587      public Builder beanProperties(String beanClassName, String properties) {
588         super.beanProperties(beanClassName, properties);
589         return this;
590      }
591
592      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
593      public Builder beanPropertiesExcludes(Map<String,Object> values) {
594         super.beanPropertiesExcludes(values);
595         return this;
596      }
597
598      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
599      public Builder beanPropertiesExcludes(Class<?> beanClass, String properties) {
600         super.beanPropertiesExcludes(beanClass, properties);
601         return this;
602      }
603
604      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
605      public Builder beanPropertiesExcludes(String beanClassName, String properties) {
606         super.beanPropertiesExcludes(beanClassName, properties);
607         return this;
608      }
609
610      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
611      public Builder beanPropertiesReadOnly(Map<String,Object> values) {
612         super.beanPropertiesReadOnly(values);
613         return this;
614      }
615
616      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
617      public Builder beanPropertiesReadOnly(Class<?> beanClass, String properties) {
618         super.beanPropertiesReadOnly(beanClass, properties);
619         return this;
620      }
621
622      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
623      public Builder beanPropertiesReadOnly(String beanClassName, String properties) {
624         super.beanPropertiesReadOnly(beanClassName, properties);
625         return this;
626      }
627
628      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
629      public Builder beanPropertiesWriteOnly(Map<String,Object> values) {
630         super.beanPropertiesWriteOnly(values);
631         return this;
632      }
633
634      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
635      public Builder beanPropertiesWriteOnly(Class<?> beanClass, String properties) {
636         super.beanPropertiesWriteOnly(beanClass, properties);
637         return this;
638      }
639
640      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
641      public Builder beanPropertiesWriteOnly(String beanClassName, String properties) {
642         super.beanPropertiesWriteOnly(beanClassName, properties);
643         return this;
644      }
645
646      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
647      public Builder beansRequireDefaultConstructor() {
648         super.beansRequireDefaultConstructor();
649         return this;
650      }
651
652      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
653      public Builder beansRequireSerializable() {
654         super.beansRequireSerializable();
655         return this;
656      }
657
658      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
659      public Builder beansRequireSettersForGetters() {
660         super.beansRequireSettersForGetters();
661         return this;
662      }
663
664      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
665      public Builder dictionaryOn(Class<?> on, java.lang.Class<?>...values) {
666         super.dictionaryOn(on, values);
667         return this;
668      }
669
670      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
671      public Builder disableBeansRequireSomeProperties() {
672         super.disableBeansRequireSomeProperties();
673         return this;
674      }
675
676      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
677      public Builder disableIgnoreMissingSetters() {
678         super.disableIgnoreMissingSetters();
679         return this;
680      }
681
682      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
683      public Builder disableIgnoreTransientFields() {
684         super.disableIgnoreTransientFields();
685         return this;
686      }
687
688      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
689      public Builder disableIgnoreUnknownNullBeanProperties() {
690         super.disableIgnoreUnknownNullBeanProperties();
691         return this;
692      }
693
694      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
695      public Builder disableInterfaceProxies() {
696         super.disableInterfaceProxies();
697         return this;
698      }
699
700      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
701      public <T> Builder example(Class<T> pojoClass, T o) {
702         super.example(pojoClass, o);
703         return this;
704      }
705
706      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
707      public <T> Builder example(Class<T> pojoClass, String json) {
708         super.example(pojoClass, json);
709         return this;
710      }
711
712      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
713      public Builder findFluentSetters() {
714         super.findFluentSetters();
715         return this;
716      }
717
718      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
719      public Builder findFluentSetters(Class<?> on) {
720         super.findFluentSetters(on);
721         return this;
722      }
723
724      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
725      public Builder ignoreInvocationExceptionsOnGetters() {
726         super.ignoreInvocationExceptionsOnGetters();
727         return this;
728      }
729
730      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
731      public Builder ignoreInvocationExceptionsOnSetters() {
732         super.ignoreInvocationExceptionsOnSetters();
733         return this;
734      }
735
736      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
737      public Builder ignoreUnknownBeanProperties() {
738         super.ignoreUnknownBeanProperties();
739         return this;
740      }
741
742      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
743      public Builder ignoreUnknownEnumValues() {
744         super.ignoreUnknownEnumValues();
745         return this;
746      }
747
748      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
749      public Builder implClass(Class<?> interfaceClass, Class<?> implClass) {
750         super.implClass(interfaceClass, implClass);
751         return this;
752      }
753
754      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
755      public Builder implClasses(Map<Class<?>,Class<?>> values) {
756         super.implClasses(values);
757         return this;
758      }
759
760      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
761      public Builder interfaceClass(Class<?> on, Class<?> value) {
762         super.interfaceClass(on, value);
763         return this;
764      }
765
766      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
767      public Builder interfaces(java.lang.Class<?>...value) {
768         super.interfaces(value);
769         return this;
770      }
771
772      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
773      public Builder locale(Locale value) {
774         super.locale(value);
775         return this;
776      }
777
778      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
779      public Builder mediaType(MediaType value) {
780         super.mediaType(value);
781         return this;
782      }
783
784      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
785      public Builder notBeanClasses(java.lang.Class<?>...values) {
786         super.notBeanClasses(values);
787         return this;
788      }
789
790      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
791      public Builder notBeanPackages(String...values) {
792         super.notBeanPackages(values);
793         return this;
794      }
795
796      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
797      public Builder propertyNamer(Class<? extends org.apache.juneau.PropertyNamer> value) {
798         super.propertyNamer(value);
799         return this;
800      }
801
802      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
803      public Builder propertyNamer(Class<?> on, Class<? extends org.apache.juneau.PropertyNamer> value) {
804         super.propertyNamer(on, value);
805         return this;
806      }
807
808      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
809      public Builder sortProperties() {
810         super.sortProperties();
811         return this;
812      }
813
814      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
815      public Builder sortProperties(java.lang.Class<?>...on) {
816         super.sortProperties(on);
817         return this;
818      }
819
820      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
821      public Builder stopClass(Class<?> on, Class<?> value) {
822         super.stopClass(on, value);
823         return this;
824      }
825
826      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
827      public <T, S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction) {
828         super.swap(normalClass, swappedClass, swapFunction);
829         return this;
830      }
831
832      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
833      public <T, S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction, ThrowingFunction<S,T> unswapFunction) {
834         super.swap(normalClass, swappedClass, swapFunction, unswapFunction);
835         return this;
836      }
837
838      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
839      public Builder swaps(java.lang.Class<?>...values) {
840         super.swaps(values);
841         return this;
842      }
843
844      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
845      public Builder timeZone(TimeZone value) {
846         super.timeZone(value);
847         return this;
848      }
849
850      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
851      public Builder typeName(Class<?> on, String value) {
852         super.typeName(on, value);
853         return this;
854      }
855
856      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
857      public Builder typePropertyName(String value) {
858         super.typePropertyName(value);
859         return this;
860      }
861
862      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
863      public Builder typePropertyName(Class<?> on, String value) {
864         super.typePropertyName(on, value);
865         return this;
866      }
867
868      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
869      public Builder useEnumNames() {
870         super.useEnumNames();
871         return this;
872      }
873
874      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
875      public Builder useJavaBeanIntrospector() {
876         super.useJavaBeanIntrospector();
877         return this;
878      }
879
880      @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */
881      public Builder detectRecursions() {
882         super.detectRecursions();
883         return this;
884      }
885
886      @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */
887      public Builder detectRecursions(boolean value) {
888         super.detectRecursions(value);
889         return this;
890      }
891
892      @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */
893      public Builder ignoreRecursions() {
894         super.ignoreRecursions();
895         return this;
896      }
897
898      @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */
899      public Builder ignoreRecursions(boolean value) {
900         super.ignoreRecursions(value);
901         return this;
902      }
903
904      @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */
905      public Builder initialDepth(int value) {
906         super.initialDepth(value);
907         return this;
908      }
909
910      @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */
911      public Builder maxDepth(int value) {
912         super.maxDepth(value);
913         return this;
914      }
915
916      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
917      public Builder accept(String value) {
918         super.accept(value);
919         return this;
920      }
921
922      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
923      public Builder addBeanTypes() {
924         super.addBeanTypes();
925         return this;
926      }
927
928      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
929      public Builder addBeanTypes(boolean value) {
930         super.addBeanTypes(value);
931         return this;
932      }
933
934      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
935      public Builder addRootType() {
936         super.addRootType();
937         return this;
938      }
939
940      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
941      public Builder addRootType(boolean value) {
942         super.addRootType(value);
943         return this;
944      }
945
946      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
947      public Builder keepNullProperties() {
948         super.keepNullProperties();
949         return this;
950      }
951
952      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
953      public Builder keepNullProperties(boolean value) {
954         super.keepNullProperties(value);
955         return this;
956      }
957
958      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
959      public Builder listener(Class<? extends org.apache.juneau.serializer.SerializerListener> value) {
960         super.listener(value);
961         return this;
962      }
963
964      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
965      public Builder produces(String value) {
966         super.produces(value);
967         return this;
968      }
969
970      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
971      public Builder sortCollections() {
972         super.sortCollections();
973         return this;
974      }
975
976      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
977      public Builder sortCollections(boolean value) {
978         super.sortCollections(value);
979         return this;
980      }
981
982      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
983      public Builder sortMaps() {
984         super.sortMaps();
985         return this;
986      }
987
988      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
989      public Builder sortMaps(boolean value) {
990         super.sortMaps(value);
991         return this;
992      }
993
994      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
995      public Builder trimEmptyCollections() {
996         super.trimEmptyCollections();
997         return this;
998      }
999
1000      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1001      public Builder trimEmptyCollections(boolean value) {
1002         super.trimEmptyCollections(value);
1003         return this;
1004      }
1005
1006      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1007      public Builder trimEmptyMaps() {
1008         super.trimEmptyMaps();
1009         return this;
1010      }
1011
1012      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1013      public Builder trimEmptyMaps(boolean value) {
1014         super.trimEmptyMaps(value);
1015         return this;
1016      }
1017
1018      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1019      public Builder trimStrings() {
1020         super.trimStrings();
1021         return this;
1022      }
1023
1024      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1025      public Builder trimStrings(boolean value) {
1026         super.trimStrings(value);
1027         return this;
1028      }
1029
1030      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1031      public Builder uriContext(UriContext value) {
1032         super.uriContext(value);
1033         return this;
1034      }
1035
1036      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1037      public Builder uriRelativity(UriRelativity value) {
1038         super.uriRelativity(value);
1039         return this;
1040      }
1041
1042      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
1043      public Builder uriResolution(UriResolution value) {
1044         super.uriResolution(value);
1045         return this;
1046      }
1047
1048      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1049      public Builder fileCharset(Charset value) {
1050         super.fileCharset(value);
1051         return this;
1052      }
1053
1054      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1055      public Builder maxIndent(int value) {
1056         super.maxIndent(value);
1057         return this;
1058      }
1059
1060      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1061      public Builder quoteChar(char value) {
1062         super.quoteChar(value);
1063         return this;
1064      }
1065
1066      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1067      public Builder quoteCharOverride(char value) {
1068         super.quoteCharOverride(value);
1069         return this;
1070      }
1071
1072      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1073      public Builder sq() {
1074         super.sq();
1075         return this;
1076      }
1077
1078      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1079      public Builder streamCharset(Charset value) {
1080         super.streamCharset(value);
1081         return this;
1082      }
1083
1084      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1085      public Builder useWhitespace() {
1086         super.useWhitespace();
1087         return this;
1088      }
1089
1090      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1091      public Builder useWhitespace(boolean value) {
1092         super.useWhitespace(value);
1093         return this;
1094      }
1095
1096      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
1097      public Builder ws() {
1098         super.ws();
1099         return this;
1100      }
1101
1102      // </FluentSetters>
1103   }
1104
1105   //-------------------------------------------------------------------------------------------------------------------
1106   // Instance
1107   //-------------------------------------------------------------------------------------------------------------------
1108
1109   final boolean
1110      encoding,
1111      addBeanTypesUon;
1112   final ParamFormat
1113      paramFormat;
1114   final Character
1115      quoteCharUon;
1116
1117   private final boolean addBeanTypes;
1118   private final char quoteChar;
1119
1120   private final Map<ClassMeta<?>,UonClassMeta> uonClassMetas = new ConcurrentHashMap<>();
1121   private final Map<BeanPropertyMeta,UonBeanPropertyMeta> uonBeanPropertyMetas = new ConcurrentHashMap<>();
1122
1123   /**
1124    * Constructor.
1125    *
1126    * @param builder
1127    *    The builder for this object.
1128    */
1129   public UonSerializer(Builder builder) {
1130      super(builder);
1131
1132      encoding = builder.encoding;
1133      addBeanTypesUon = builder.addBeanTypesUon;
1134      paramFormat = builder.paramFormat;
1135      quoteCharUon = builder.quoteCharUon;
1136
1137      addBeanTypes = addBeanTypesUon || super.isAddBeanTypes();
1138      quoteChar = quoteCharUon != null ? quoteCharUon : super.quoteChar() != null ? super.quoteChar() : '\'';
1139   }
1140
1141   @Override /* Context */
1142   public Builder copy() {
1143      return new Builder(this);
1144   }
1145
1146   @Override /* Context */
1147   public  UonSerializerSession.Builder createSession() {
1148      return UonSerializerSession.create(this);
1149   }
1150
1151   @Override /* Context */
1152   public UonSerializerSession getSession() {
1153      return createSession().build();
1154   }
1155
1156   @Override /* HttpPartSerializer */
1157   public UonSerializerSession getPartSession() {
1158      return UonSerializerSession.create(this).build();
1159   }
1160
1161   //-----------------------------------------------------------------------------------------------------------------
1162   // Extended metadata
1163   //-----------------------------------------------------------------------------------------------------------------
1164
1165   @Override /* UonMetaProvider */
1166   public UonClassMeta getUonClassMeta(ClassMeta<?> cm) {
1167      UonClassMeta m = uonClassMetas.get(cm);
1168      if (m == null) {
1169         m = new UonClassMeta(cm, this);
1170         uonClassMetas.put(cm, m);
1171      }
1172      return m;
1173   }
1174
1175   @Override /* UonMetaProvider */
1176   public UonBeanPropertyMeta getUonBeanPropertyMeta(BeanPropertyMeta bpm) {
1177      if (bpm == null)
1178         return UonBeanPropertyMeta.DEFAULT;
1179      UonBeanPropertyMeta m = uonBeanPropertyMetas.get(bpm);
1180      if (m == null) {
1181         m = new UonBeanPropertyMeta(bpm.getDelegateFor(), this);
1182         uonBeanPropertyMetas.put(bpm, m);
1183      }
1184      return m;
1185   }
1186
1187   //-----------------------------------------------------------------------------------------------------------------
1188   // Properties
1189   //-----------------------------------------------------------------------------------------------------------------
1190
1191   /**
1192    * Add <js>"_type"</js> properties when needed.
1193    *
1194    * @see Builder#addBeanTypesUon()
1195    * @return
1196    *    <jk>true</jk> if <js>"_type"</js> properties will be added to beans if their type cannot be inferred
1197    *    through reflection.
1198    */
1199   @Override
1200   protected final boolean isAddBeanTypes() {
1201      return addBeanTypes;
1202   }
1203
1204   /**
1205    * Encode non-valid URI characters.
1206    *
1207    * @see Builder#encoding()
1208    * @return
1209    *    <jk>true</jk> if non-valid URI characters should be encoded with <js>"%xx"</js> constructs.
1210    */
1211   protected final boolean isEncoding() {
1212      return encoding;
1213   }
1214
1215   /**
1216    * Format to use for query/form-data/header values.
1217    *
1218    * @see Builder#paramFormat(ParamFormat)
1219    * @return
1220    *    Specifies the format to use for URL GET parameter keys and values.
1221    */
1222   protected final ParamFormat getParamFormat() {
1223      return paramFormat;
1224   }
1225
1226   /**
1227    * Quote character.
1228    *
1229    * @see Builder#quoteCharUon(char)
1230    * @return
1231    *    The character used for quoting attributes and values.
1232    */
1233   @Override
1234   protected final char getQuoteChar() {
1235      return quoteChar;
1236   }
1237
1238   //-----------------------------------------------------------------------------------------------------------------
1239   // Other methods
1240   //-----------------------------------------------------------------------------------------------------------------
1241
1242   @Override /* Context */
1243   protected JsonMap properties() {
1244      return filteredMap("encoding", encoding, "addBeanTypes", addBeanTypes, "paramFormat", paramFormat);
1245   }
1246}