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         super();
225         produces("application/x-www-form-urlencoded");
226         expandedParams = env("UrlEncoding.expandedParams", false);
227      }
228
229      /**
230       * Copy constructor.
231       *
232       * @param copyFrom The bean to copy from.
233       */
234      protected Builder(UrlEncodingSerializer copyFrom) {
235         super(copyFrom);
236         expandedParams = copyFrom.expandedParams;
237      }
238
239      /**
240       * Copy constructor.
241       *
242       * @param copyFrom The builder to copy from.
243       */
244      protected Builder(Builder copyFrom) {
245         super(copyFrom);
246         expandedParams = copyFrom.expandedParams;
247      }
248
249      @Override /* Context.Builder */
250      public Builder copy() {
251         return new Builder(this);
252      }
253
254      @Override /* Context.Builder */
255      public UrlEncodingSerializer build() {
256         return cache(CACHE).build(UrlEncodingSerializer.class);
257      }
258
259      @Override /* Context.Builder */
260      public HashKey hashKey() {
261         return HashKey.of(
262            super.hashKey(),
263            expandedParams
264         );
265      }
266
267      //-----------------------------------------------------------------------------------------------------------------
268      // Properties
269      //-----------------------------------------------------------------------------------------------------------------
270
271      /**
272       * Serialize bean property collections/arrays as separate key/value pairs.
273       *
274       * <p>
275       * By default, serializing the array <c>[1,2,3]</c> results in <c>?key=$a(1,2,3)</c>.
276       * <br>When enabled, serializing the same array results in <c>?key=1&amp;key=2&amp;key=3</c>.
277       *
278       * <p>
279       * This option only applies to beans.
280       *
281       * <h5 class='section'>Notes:</h5><ul>
282       *    <li class='note'>
283       *       If parsing multi-part parameters, it's highly recommended to use <c>Collections</c> or <c>Lists</c>
284       *       as bean property types instead of arrays since arrays have to be recreated from scratch every time a value
285       *       is added to it.
286       * </ul>
287       *
288       * <h5 class='section'>Example:</h5>
289       * <p class='bjava'>
290       *    <jc>// A sample bean.</jc>
291       *    <jk>public class</jk> A {
292       *       <jk>public</jk> String[] <jf>f1</jf> = {<js>"a"</js>,<js>"b"</js>};
293       *       <jk>public</jk> List&lt;String&gt; <jf>f2</jf> = Arrays.<jsm>asList</jsm>(<jk>new</jk> String[]{<js>"c"</js>,<js>"d"</js>});
294       *    }
295       *
296       *    <jc>// Normal serializer.</jc>
297       *    WriterSerializer <jv>serializer1</jv> = UrlEncodingSerializer.<jsf>DEFAULT</jsf>;
298       *
299       *    <jc>// Expanded-params serializer.</jc>
300       *    WriterSerializer <jv>serializer2</jv> = UrlEncodingSerializer.<jsm>create</jsm>().expandedParams().build();
301       *
302       *  <jc>// Produces "f1=(a,b)&amp;f2=(c,d)"</jc>
303       *    String <jv>out1</jv> = <jv>serializer1</jv>.serialize(<jk>new</jk> A());
304       *
305       *    <jc>// Produces "f1=a&amp;f1=b&amp;f2=c&amp;f2=d"</jc>
306       *    String <jv>out2</jv> = <jv>serializer2</jv>.serialize(<jk>new</jk> A());
307       * </p>
308       *
309       * @return This object.
310       */
311      @FluentSetter
312      public Builder expandedParams() {
313         return expandedParams(true);
314      }
315
316      /**
317       * Same as {@link #expandedParams()} but allows you to explicitly specify the value.
318       *
319       * @param value The value for this setting.
320       * @return This object.
321       */
322      @FluentSetter
323      public Builder expandedParams(boolean value) {
324         expandedParams = value;
325         return this;
326      }
327
328      // <FluentSetters>
329
330      @Override /* GENERATED - org.apache.juneau.Context.Builder */
331      public Builder annotations(Annotation...values) {
332         super.annotations(values);
333         return this;
334      }
335
336      @Override /* GENERATED - org.apache.juneau.Context.Builder */
337      public Builder apply(AnnotationWorkList work) {
338         super.apply(work);
339         return this;
340      }
341
342      @Override /* GENERATED - org.apache.juneau.Context.Builder */
343      public Builder applyAnnotations(java.lang.Class<?>...fromClasses) {
344         super.applyAnnotations(fromClasses);
345         return this;
346      }
347
348      @Override /* GENERATED - org.apache.juneau.Context.Builder */
349      public Builder applyAnnotations(Method...fromMethods) {
350         super.applyAnnotations(fromMethods);
351         return this;
352      }
353
354      @Override /* GENERATED - org.apache.juneau.Context.Builder */
355      public Builder cache(Cache<HashKey,? extends org.apache.juneau.Context> value) {
356         super.cache(value);
357         return this;
358      }
359
360      @Override /* GENERATED - org.apache.juneau.Context.Builder */
361      public Builder debug() {
362         super.debug();
363         return this;
364      }
365
366      @Override /* GENERATED - org.apache.juneau.Context.Builder */
367      public Builder debug(boolean value) {
368         super.debug(value);
369         return this;
370      }
371
372      @Override /* GENERATED - org.apache.juneau.Context.Builder */
373      public Builder impl(Context value) {
374         super.impl(value);
375         return this;
376      }
377
378      @Override /* GENERATED - org.apache.juneau.Context.Builder */
379      public Builder type(Class<? extends org.apache.juneau.Context> value) {
380         super.type(value);
381         return this;
382      }
383
384      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
385      public Builder beanClassVisibility(Visibility value) {
386         super.beanClassVisibility(value);
387         return this;
388      }
389
390      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
391      public Builder beanConstructorVisibility(Visibility value) {
392         super.beanConstructorVisibility(value);
393         return this;
394      }
395
396      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
397      public Builder beanContext(BeanContext value) {
398         super.beanContext(value);
399         return this;
400      }
401
402      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
403      public Builder beanContext(BeanContext.Builder value) {
404         super.beanContext(value);
405         return this;
406      }
407
408      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
409      public Builder beanDictionary(java.lang.Class<?>...values) {
410         super.beanDictionary(values);
411         return this;
412      }
413
414      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
415      public Builder beanFieldVisibility(Visibility value) {
416         super.beanFieldVisibility(value);
417         return this;
418      }
419
420      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
421      public Builder beanInterceptor(Class<?> on, Class<? extends org.apache.juneau.swap.BeanInterceptor<?>> value) {
422         super.beanInterceptor(on, value);
423         return this;
424      }
425
426      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
427      public Builder beanMapPutReturnsOldValue() {
428         super.beanMapPutReturnsOldValue();
429         return this;
430      }
431
432      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
433      public Builder beanMethodVisibility(Visibility value) {
434         super.beanMethodVisibility(value);
435         return this;
436      }
437
438      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
439      public Builder beanProperties(Map<String,Object> values) {
440         super.beanProperties(values);
441         return this;
442      }
443
444      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
445      public Builder beanProperties(Class<?> beanClass, String properties) {
446         super.beanProperties(beanClass, properties);
447         return this;
448      }
449
450      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
451      public Builder beanProperties(String beanClassName, String properties) {
452         super.beanProperties(beanClassName, properties);
453         return this;
454      }
455
456      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
457      public Builder beanPropertiesExcludes(Map<String,Object> values) {
458         super.beanPropertiesExcludes(values);
459         return this;
460      }
461
462      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
463      public Builder beanPropertiesExcludes(Class<?> beanClass, String properties) {
464         super.beanPropertiesExcludes(beanClass, properties);
465         return this;
466      }
467
468      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
469      public Builder beanPropertiesExcludes(String beanClassName, String properties) {
470         super.beanPropertiesExcludes(beanClassName, properties);
471         return this;
472      }
473
474      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
475      public Builder beanPropertiesReadOnly(Map<String,Object> values) {
476         super.beanPropertiesReadOnly(values);
477         return this;
478      }
479
480      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
481      public Builder beanPropertiesReadOnly(Class<?> beanClass, String properties) {
482         super.beanPropertiesReadOnly(beanClass, properties);
483         return this;
484      }
485
486      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
487      public Builder beanPropertiesReadOnly(String beanClassName, String properties) {
488         super.beanPropertiesReadOnly(beanClassName, properties);
489         return this;
490      }
491
492      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
493      public Builder beanPropertiesWriteOnly(Map<String,Object> values) {
494         super.beanPropertiesWriteOnly(values);
495         return this;
496      }
497
498      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
499      public Builder beanPropertiesWriteOnly(Class<?> beanClass, String properties) {
500         super.beanPropertiesWriteOnly(beanClass, properties);
501         return this;
502      }
503
504      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
505      public Builder beanPropertiesWriteOnly(String beanClassName, String properties) {
506         super.beanPropertiesWriteOnly(beanClassName, properties);
507         return this;
508      }
509
510      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
511      public Builder beansRequireDefaultConstructor() {
512         super.beansRequireDefaultConstructor();
513         return this;
514      }
515
516      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
517      public Builder beansRequireSerializable() {
518         super.beansRequireSerializable();
519         return this;
520      }
521
522      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
523      public Builder beansRequireSettersForGetters() {
524         super.beansRequireSettersForGetters();
525         return this;
526      }
527
528      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
529      public Builder dictionaryOn(Class<?> on, java.lang.Class<?>...values) {
530         super.dictionaryOn(on, values);
531         return this;
532      }
533
534      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
535      public Builder disableBeansRequireSomeProperties() {
536         super.disableBeansRequireSomeProperties();
537         return this;
538      }
539
540      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
541      public Builder disableIgnoreMissingSetters() {
542         super.disableIgnoreMissingSetters();
543         return this;
544      }
545
546      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
547      public Builder disableIgnoreTransientFields() {
548         super.disableIgnoreTransientFields();
549         return this;
550      }
551
552      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
553      public Builder disableIgnoreUnknownNullBeanProperties() {
554         super.disableIgnoreUnknownNullBeanProperties();
555         return this;
556      }
557
558      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
559      public Builder disableInterfaceProxies() {
560         super.disableInterfaceProxies();
561         return this;
562      }
563
564      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
565      public <T> Builder example(Class<T> pojoClass, T o) {
566         super.example(pojoClass, o);
567         return this;
568      }
569
570      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
571      public <T> Builder example(Class<T> pojoClass, String json) {
572         super.example(pojoClass, json);
573         return this;
574      }
575
576      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
577      public Builder findFluentSetters() {
578         super.findFluentSetters();
579         return this;
580      }
581
582      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
583      public Builder findFluentSetters(Class<?> on) {
584         super.findFluentSetters(on);
585         return this;
586      }
587
588      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
589      public Builder ignoreInvocationExceptionsOnGetters() {
590         super.ignoreInvocationExceptionsOnGetters();
591         return this;
592      }
593
594      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
595      public Builder ignoreInvocationExceptionsOnSetters() {
596         super.ignoreInvocationExceptionsOnSetters();
597         return this;
598      }
599
600      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
601      public Builder ignoreUnknownBeanProperties() {
602         super.ignoreUnknownBeanProperties();
603         return this;
604      }
605
606      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
607      public Builder ignoreUnknownEnumValues() {
608         super.ignoreUnknownEnumValues();
609         return this;
610      }
611
612      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
613      public Builder implClass(Class<?> interfaceClass, Class<?> implClass) {
614         super.implClass(interfaceClass, implClass);
615         return this;
616      }
617
618      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
619      public Builder implClasses(Map<Class<?>,Class<?>> values) {
620         super.implClasses(values);
621         return this;
622      }
623
624      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
625      public Builder interfaceClass(Class<?> on, Class<?> value) {
626         super.interfaceClass(on, value);
627         return this;
628      }
629
630      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
631      public Builder interfaces(java.lang.Class<?>...value) {
632         super.interfaces(value);
633         return this;
634      }
635
636      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
637      public Builder locale(Locale value) {
638         super.locale(value);
639         return this;
640      }
641
642      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
643      public Builder mediaType(MediaType value) {
644         super.mediaType(value);
645         return this;
646      }
647
648      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
649      public Builder notBeanClasses(java.lang.Class<?>...values) {
650         super.notBeanClasses(values);
651         return this;
652      }
653
654      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
655      public Builder notBeanPackages(String...values) {
656         super.notBeanPackages(values);
657         return this;
658      }
659
660      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
661      public Builder propertyNamer(Class<? extends org.apache.juneau.PropertyNamer> value) {
662         super.propertyNamer(value);
663         return this;
664      }
665
666      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
667      public Builder propertyNamer(Class<?> on, Class<? extends org.apache.juneau.PropertyNamer> value) {
668         super.propertyNamer(on, value);
669         return this;
670      }
671
672      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
673      public Builder sortProperties() {
674         super.sortProperties();
675         return this;
676      }
677
678      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
679      public Builder sortProperties(java.lang.Class<?>...on) {
680         super.sortProperties(on);
681         return this;
682      }
683
684      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
685      public Builder stopClass(Class<?> on, Class<?> value) {
686         super.stopClass(on, value);
687         return this;
688      }
689
690      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
691      public <T, S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction) {
692         super.swap(normalClass, swappedClass, swapFunction);
693         return this;
694      }
695
696      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
697      public <T, S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction, ThrowingFunction<S,T> unswapFunction) {
698         super.swap(normalClass, swappedClass, swapFunction, unswapFunction);
699         return this;
700      }
701
702      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
703      public Builder swaps(java.lang.Class<?>...values) {
704         super.swaps(values);
705         return this;
706      }
707
708      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
709      public Builder timeZone(TimeZone value) {
710         super.timeZone(value);
711         return this;
712      }
713
714      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
715      public Builder typeName(Class<?> on, String value) {
716         super.typeName(on, value);
717         return this;
718      }
719
720      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
721      public Builder typePropertyName(String value) {
722         super.typePropertyName(value);
723         return this;
724      }
725
726      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
727      public Builder typePropertyName(Class<?> on, String value) {
728         super.typePropertyName(on, value);
729         return this;
730      }
731
732      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
733      public Builder useEnumNames() {
734         super.useEnumNames();
735         return this;
736      }
737
738      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
739      public Builder useJavaBeanIntrospector() {
740         super.useJavaBeanIntrospector();
741         return this;
742      }
743
744      @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */
745      public Builder detectRecursions() {
746         super.detectRecursions();
747         return this;
748      }
749
750      @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */
751      public Builder detectRecursions(boolean value) {
752         super.detectRecursions(value);
753         return this;
754      }
755
756      @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */
757      public Builder ignoreRecursions() {
758         super.ignoreRecursions();
759         return this;
760      }
761
762      @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */
763      public Builder ignoreRecursions(boolean value) {
764         super.ignoreRecursions(value);
765         return this;
766      }
767
768      @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */
769      public Builder initialDepth(int value) {
770         super.initialDepth(value);
771         return this;
772      }
773
774      @Override /* GENERATED - org.apache.juneau.BeanTraverseContext.Builder */
775      public Builder maxDepth(int value) {
776         super.maxDepth(value);
777         return this;
778      }
779
780      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
781      public Builder accept(String value) {
782         super.accept(value);
783         return this;
784      }
785
786      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
787      public Builder addBeanTypes() {
788         super.addBeanTypes();
789         return this;
790      }
791
792      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
793      public Builder addBeanTypes(boolean value) {
794         super.addBeanTypes(value);
795         return this;
796      }
797
798      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
799      public Builder addRootType() {
800         super.addRootType();
801         return this;
802      }
803
804      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
805      public Builder addRootType(boolean value) {
806         super.addRootType(value);
807         return this;
808      }
809
810      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
811      public Builder keepNullProperties() {
812         super.keepNullProperties();
813         return this;
814      }
815
816      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
817      public Builder keepNullProperties(boolean value) {
818         super.keepNullProperties(value);
819         return this;
820      }
821
822      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
823      public Builder listener(Class<? extends org.apache.juneau.serializer.SerializerListener> value) {
824         super.listener(value);
825         return this;
826      }
827
828      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
829      public Builder produces(String value) {
830         super.produces(value);
831         return this;
832      }
833
834      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
835      public Builder sortCollections() {
836         super.sortCollections();
837         return this;
838      }
839
840      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
841      public Builder sortCollections(boolean value) {
842         super.sortCollections(value);
843         return this;
844      }
845
846      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
847      public Builder sortMaps() {
848         super.sortMaps();
849         return this;
850      }
851
852      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
853      public Builder sortMaps(boolean value) {
854         super.sortMaps(value);
855         return this;
856      }
857
858      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
859      public Builder trimEmptyCollections() {
860         super.trimEmptyCollections();
861         return this;
862      }
863
864      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
865      public Builder trimEmptyCollections(boolean value) {
866         super.trimEmptyCollections(value);
867         return this;
868      }
869
870      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
871      public Builder trimEmptyMaps() {
872         super.trimEmptyMaps();
873         return this;
874      }
875
876      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
877      public Builder trimEmptyMaps(boolean value) {
878         super.trimEmptyMaps(value);
879         return this;
880      }
881
882      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
883      public Builder trimStrings() {
884         super.trimStrings();
885         return this;
886      }
887
888      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
889      public Builder trimStrings(boolean value) {
890         super.trimStrings(value);
891         return this;
892      }
893
894      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
895      public Builder uriContext(UriContext value) {
896         super.uriContext(value);
897         return this;
898      }
899
900      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
901      public Builder uriRelativity(UriRelativity value) {
902         super.uriRelativity(value);
903         return this;
904      }
905
906      @Override /* GENERATED - org.apache.juneau.serializer.Serializer.Builder */
907      public Builder uriResolution(UriResolution value) {
908         super.uriResolution(value);
909         return this;
910      }
911
912      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
913      public Builder fileCharset(Charset value) {
914         super.fileCharset(value);
915         return this;
916      }
917
918      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
919      public Builder maxIndent(int value) {
920         super.maxIndent(value);
921         return this;
922      }
923
924      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
925      public Builder quoteChar(char value) {
926         super.quoteChar(value);
927         return this;
928      }
929
930      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
931      public Builder quoteCharOverride(char value) {
932         super.quoteCharOverride(value);
933         return this;
934      }
935
936      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
937      public Builder sq() {
938         super.sq();
939         return this;
940      }
941
942      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
943      public Builder streamCharset(Charset value) {
944         super.streamCharset(value);
945         return this;
946      }
947
948      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
949      public Builder useWhitespace() {
950         super.useWhitespace();
951         return this;
952      }
953
954      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
955      public Builder useWhitespace(boolean value) {
956         super.useWhitespace(value);
957         return this;
958      }
959
960      @Override /* GENERATED - org.apache.juneau.serializer.WriterSerializer.Builder */
961      public Builder ws() {
962         super.ws();
963         return this;
964      }
965
966      @Override /* GENERATED - org.apache.juneau.uon.UonSerializer.Builder */
967      public Builder addBeanTypesUon() {
968         super.addBeanTypesUon();
969         return this;
970      }
971
972      @Override /* GENERATED - org.apache.juneau.uon.UonSerializer.Builder */
973      public Builder addBeanTypesUon(boolean value) {
974         super.addBeanTypesUon(value);
975         return this;
976      }
977
978      @Override /* GENERATED - org.apache.juneau.uon.UonSerializer.Builder */
979      public Builder encoding() {
980         super.encoding();
981         return this;
982      }
983
984      @Override /* GENERATED - org.apache.juneau.uon.UonSerializer.Builder */
985      public Builder paramFormat(ParamFormat value) {
986         super.paramFormat(value);
987         return this;
988      }
989
990      @Override /* GENERATED - org.apache.juneau.uon.UonSerializer.Builder */
991      public Builder paramFormatPlain() {
992         super.paramFormatPlain();
993         return this;
994      }
995
996      @Override /* GENERATED - org.apache.juneau.uon.UonSerializer.Builder */
997      public Builder quoteCharUon(char value) {
998         super.quoteCharUon(value);
999         return this;
1000      }
1001
1002      // </FluentSetters>
1003   }
1004
1005   //-------------------------------------------------------------------------------------------------------------------
1006   // Instance
1007   //-------------------------------------------------------------------------------------------------------------------
1008
1009   final boolean
1010      expandedParams;
1011
1012   private final Map<ClassMeta<?>,UrlEncodingClassMeta> urlEncodingClassMetas = new ConcurrentHashMap<>();
1013   private final Map<BeanPropertyMeta,UrlEncodingBeanPropertyMeta> urlEncodingBeanPropertyMetas = new ConcurrentHashMap<>();
1014
1015   /**
1016    * Constructor.
1017    *
1018    * @param builder The builder for this object.
1019    */
1020   public UrlEncodingSerializer(Builder builder) {
1021      super(builder.encoding());
1022      expandedParams = builder.expandedParams;
1023   }
1024
1025   @Override /* Context */
1026   public Builder copy() {
1027      return new Builder(this);
1028   }
1029
1030   @Override /* Context */
1031   public UrlEncodingSerializerSession.Builder createSession() {
1032      return UrlEncodingSerializerSession.create(this);
1033   }
1034
1035   @Override /* Context */
1036   public UrlEncodingSerializerSession getSession() {
1037      return createSession().build();
1038   }
1039
1040   //-----------------------------------------------------------------------------------------------------------------
1041   // Extended metadata
1042   //-----------------------------------------------------------------------------------------------------------------
1043
1044   @Override /* UrlEncodingMetaProvider */
1045   public UrlEncodingClassMeta getUrlEncodingClassMeta(ClassMeta<?> cm) {
1046      UrlEncodingClassMeta m = urlEncodingClassMetas.get(cm);
1047      if (m == null) {
1048         m = new UrlEncodingClassMeta(cm, this);
1049         urlEncodingClassMetas.put(cm, m);
1050      }
1051      return m;
1052   }
1053
1054   @Override /* UrlEncodingMetaProvider */
1055   public UrlEncodingBeanPropertyMeta getUrlEncodingBeanPropertyMeta(BeanPropertyMeta bpm) {
1056      if (bpm == null)
1057         return UrlEncodingBeanPropertyMeta.DEFAULT;
1058      UrlEncodingBeanPropertyMeta m = urlEncodingBeanPropertyMetas.get(bpm);
1059      if (m == null) {
1060         m = new UrlEncodingBeanPropertyMeta(bpm.getDelegateFor(), this);
1061         urlEncodingBeanPropertyMetas.put(bpm, m);
1062      }
1063      return m;
1064   }
1065
1066   //-----------------------------------------------------------------------------------------------------------------
1067   // Properties
1068   //-----------------------------------------------------------------------------------------------------------------
1069
1070   /**
1071    * Serialize bean property collections/arrays as separate key/value pairs.
1072    *
1073    * @see Builder#expandedParams()
1074    * @return
1075    *    <jk>false</jk> if serializing the array <c>[1,2,3]</c> results in <c>?key=$a(1,2,3)</c>.
1076    *    <br><jk>true</jk> if serializing the same array results in <c>?key=1&amp;key=2&amp;key=3</c>.
1077    */
1078   protected final boolean isExpandedParams() {
1079      return expandedParams;
1080   }
1081
1082   //-----------------------------------------------------------------------------------------------------------------
1083   // Other methods
1084   //-----------------------------------------------------------------------------------------------------------------
1085
1086   @Override /* Context */
1087   protected JsonMap properties() {
1088      return filteredMap("expandedParams", expandedParams);
1089   }
1090}