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