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