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 * Parses URL-encoded text into POJO models.
030 *
031 * <h5 class='topic'>Media types</h5>
032 * <p>
033 * Handles <c>Content-Type</c> types:  <bc>application/x-www-form-urlencoded</bc>
034 *
035 * <h5 class='topic'>Description</h5>
036 * <p>
037 * Parses URL-Encoded text (e.g. <js>"foo=bar&amp;baz=bing"</js>) into POJOs.
038 *
039 * <p>
040 * Expects parameter values to be in UON notation.
041 *
042 * <p>
043 * This parser uses a state machine, which makes it very fast and efficient.
044 *
045 * <h5 class='section'>Notes:</h5><ul>
046 *    <li class='note'>This class is thread safe and reusable.
047 * </ul>
048 *
049 * <h5 class='section'>See Also:</h5><ul>
050 *    <li class='link'><a class="doclink" href="../../../../index.html#jm.UrlEncodingDetails">URL-Encoding Details</a>
051 * </ul>
052 */
053public class UrlEncodingParser extends UonParser implements UrlEncodingMetaProvider {
054
055   //-------------------------------------------------------------------------------------------------------------------
056   // Static
057   //-------------------------------------------------------------------------------------------------------------------
058
059   /** Reusable instance of {@link UrlEncodingParser}. */
060   public static final UrlEncodingParser DEFAULT = new UrlEncodingParser(create());
061
062   /**
063    * Creates a new builder for this object.
064    *
065    * @return A new builder.
066    */
067   public static Builder create() {
068      return new Builder();
069   }
070
071   //-------------------------------------------------------------------------------------------------------------------
072   // Builder
073   //-------------------------------------------------------------------------------------------------------------------
074
075   /**
076    * Builder class.
077    */
078   @FluentSetters
079   public static class Builder extends UonParser.Builder {
080
081      private static final Cache<HashKey,UrlEncodingParser> CACHE = Cache.of(HashKey.class, UrlEncodingParser.class).build();
082
083      boolean expandedParams;
084
085      /**
086       * Constructor, default settings.
087       */
088      protected Builder() {
089         decoding();
090         consumes("application/x-www-form-urlencoded");
091         expandedParams = env("UrlEncoding.expandedParams", false);
092      }
093
094      /**
095       * Copy constructor.
096       *
097       * @param copyFrom The bean to copy from.
098       */
099      protected Builder(UrlEncodingParser copyFrom) {
100         super(copyFrom);
101         expandedParams = copyFrom.expandedParams;
102      }
103
104      /**
105       * Copy constructor.
106       *
107       * @param copyFrom The builder to copy from.
108       */
109      protected Builder(Builder copyFrom) {
110         super(copyFrom);
111         expandedParams = copyFrom.expandedParams;
112      }
113
114      @Override /* Context.Builder */
115      public Builder copy() {
116         return new Builder(this);
117      }
118
119      @Override /* Context.Builder */
120      public UrlEncodingParser build() {
121         return cache(CACHE).build(UrlEncodingParser.class);
122      }
123
124      @Override /* Context.Builder */
125      public HashKey hashKey() {
126         return HashKey.of(
127            super.hashKey(),
128            expandedParams
129         );
130      }
131
132      //-----------------------------------------------------------------------------------------------------------------
133      // Properties
134      //-----------------------------------------------------------------------------------------------------------------
135
136      /**
137       * Serialize bean property collections/arrays as separate key/value pairs.
138       *
139       * <p>
140       * This is the parser-side equivalent of the {@link UrlEncodingSerializer.Builder#expandedParams()} setting.
141       *
142       * <p>
143       * If <jk>false</jk>, serializing the array <c>[1,2,3]</c> results in <c>?key=$a(1,2,3)</c>.
144       * <br>If <jk>true</jk>, serializing the same array results in <c>?key=1&amp;key=2&amp;key=3</c>.
145       *
146       * <h5 class='section'>Example:</h5>
147       * <p class='bjava'>
148       *    <jk>public class</jk> MyBean {
149       *       <jk>public</jk> String[] <jf>f1</jf>;
150       *       <jk>public</jk> List&lt;String&gt; <jf>f2</jf>;
151       *    }
152       *
153       *    UrlEncodingParser <jv>parser1</jv> = UrlEncodingParser.<jsf>DEFAULT</jsf>;
154       *    UrlEncodingParser <jv>parser2</jv> = UrlEncodingParser.<jsm>create</jsm>().expandedParams().build();
155       *
156       *    MyBean <jv>myBean1</jv> = <jv>parser1</jv>.parse(<js>"f1=@(a,b)&amp;f2=@(c,d)"</js>, A.<jk>class</jk>);
157       *
158       *    MyBean <jv>myBean2</jv> = <jv>parser2</jv>.parse(<js>"f1=a&amp;f1=b&amp;f2=c&amp;f2=d"</js>, A.<jk>class</jk>);
159       * </p>
160       *
161       * <p>
162       * This option only applies to beans.
163       *
164       * <h5 class='section'>Notes:</h5><ul>
165       *    <li class='note'>
166       *       If parsing multi-part parameters, it's highly recommended to use Collections or Lists
167       *       as bean property types instead of arrays since arrays have to be recreated from scratch every time a value
168       *       is added to it.
169       * </ul>
170       *
171       * @return This object.
172       */
173      @FluentSetter
174      public Builder expandedParams() {
175         return expandedParams(true);
176      }
177
178      /**
179       * Same as {@link #expandedParams()} but allows you to explicitly specify the value.
180       *
181       * @param value The value for this setting.
182       * @return This object.
183       */
184      @FluentSetter
185      public Builder expandedParams(boolean value) {
186         expandedParams = value;
187         return this;
188      }
189
190      // <FluentSetters>
191
192      @Override /* GENERATED - org.apache.juneau.Context.Builder */
193      public Builder annotations(Annotation...values) {
194         super.annotations(values);
195         return this;
196      }
197
198      @Override /* GENERATED - org.apache.juneau.Context.Builder */
199      public Builder apply(AnnotationWorkList work) {
200         super.apply(work);
201         return this;
202      }
203
204      @Override /* GENERATED - org.apache.juneau.Context.Builder */
205      public Builder applyAnnotations(java.lang.Class<?>...fromClasses) {
206         super.applyAnnotations(fromClasses);
207         return this;
208      }
209
210      @Override /* GENERATED - org.apache.juneau.Context.Builder */
211      public Builder applyAnnotations(Method...fromMethods) {
212         super.applyAnnotations(fromMethods);
213         return this;
214      }
215
216      @Override /* GENERATED - org.apache.juneau.Context.Builder */
217      public Builder cache(Cache<HashKey,? extends org.apache.juneau.Context> value) {
218         super.cache(value);
219         return this;
220      }
221
222      @Override /* GENERATED - org.apache.juneau.Context.Builder */
223      public Builder debug() {
224         super.debug();
225         return this;
226      }
227
228      @Override /* GENERATED - org.apache.juneau.Context.Builder */
229      public Builder debug(boolean value) {
230         super.debug(value);
231         return this;
232      }
233
234      @Override /* GENERATED - org.apache.juneau.Context.Builder */
235      public Builder impl(Context value) {
236         super.impl(value);
237         return this;
238      }
239
240      @Override /* GENERATED - org.apache.juneau.Context.Builder */
241      public Builder type(Class<? extends org.apache.juneau.Context> value) {
242         super.type(value);
243         return this;
244      }
245
246      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
247      public Builder beanClassVisibility(Visibility value) {
248         super.beanClassVisibility(value);
249         return this;
250      }
251
252      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
253      public Builder beanConstructorVisibility(Visibility value) {
254         super.beanConstructorVisibility(value);
255         return this;
256      }
257
258      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
259      public Builder beanContext(BeanContext value) {
260         super.beanContext(value);
261         return this;
262      }
263
264      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
265      public Builder beanContext(BeanContext.Builder value) {
266         super.beanContext(value);
267         return this;
268      }
269
270      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
271      public Builder beanDictionary(java.lang.Class<?>...values) {
272         super.beanDictionary(values);
273         return this;
274      }
275
276      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
277      public Builder beanFieldVisibility(Visibility value) {
278         super.beanFieldVisibility(value);
279         return this;
280      }
281
282      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
283      public Builder beanInterceptor(Class<?> on, Class<? extends org.apache.juneau.swap.BeanInterceptor<?>> value) {
284         super.beanInterceptor(on, value);
285         return this;
286      }
287
288      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
289      public Builder beanMapPutReturnsOldValue() {
290         super.beanMapPutReturnsOldValue();
291         return this;
292      }
293
294      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
295      public Builder beanMethodVisibility(Visibility value) {
296         super.beanMethodVisibility(value);
297         return this;
298      }
299
300      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
301      public Builder beanProperties(Map<String,Object> values) {
302         super.beanProperties(values);
303         return this;
304      }
305
306      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
307      public Builder beanProperties(Class<?> beanClass, String properties) {
308         super.beanProperties(beanClass, properties);
309         return this;
310      }
311
312      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
313      public Builder beanProperties(String beanClassName, String properties) {
314         super.beanProperties(beanClassName, properties);
315         return this;
316      }
317
318      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
319      public Builder beanPropertiesExcludes(Map<String,Object> values) {
320         super.beanPropertiesExcludes(values);
321         return this;
322      }
323
324      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
325      public Builder beanPropertiesExcludes(Class<?> beanClass, String properties) {
326         super.beanPropertiesExcludes(beanClass, properties);
327         return this;
328      }
329
330      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
331      public Builder beanPropertiesExcludes(String beanClassName, String properties) {
332         super.beanPropertiesExcludes(beanClassName, properties);
333         return this;
334      }
335
336      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
337      public Builder beanPropertiesReadOnly(Map<String,Object> values) {
338         super.beanPropertiesReadOnly(values);
339         return this;
340      }
341
342      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
343      public Builder beanPropertiesReadOnly(Class<?> beanClass, String properties) {
344         super.beanPropertiesReadOnly(beanClass, properties);
345         return this;
346      }
347
348      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
349      public Builder beanPropertiesReadOnly(String beanClassName, String properties) {
350         super.beanPropertiesReadOnly(beanClassName, properties);
351         return this;
352      }
353
354      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
355      public Builder beanPropertiesWriteOnly(Map<String,Object> values) {
356         super.beanPropertiesWriteOnly(values);
357         return this;
358      }
359
360      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
361      public Builder beanPropertiesWriteOnly(Class<?> beanClass, String properties) {
362         super.beanPropertiesWriteOnly(beanClass, properties);
363         return this;
364      }
365
366      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
367      public Builder beanPropertiesWriteOnly(String beanClassName, String properties) {
368         super.beanPropertiesWriteOnly(beanClassName, properties);
369         return this;
370      }
371
372      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
373      public Builder beansRequireDefaultConstructor() {
374         super.beansRequireDefaultConstructor();
375         return this;
376      }
377
378      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
379      public Builder beansRequireSerializable() {
380         super.beansRequireSerializable();
381         return this;
382      }
383
384      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
385      public Builder beansRequireSettersForGetters() {
386         super.beansRequireSettersForGetters();
387         return this;
388      }
389
390      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
391      public Builder dictionaryOn(Class<?> on, java.lang.Class<?>...values) {
392         super.dictionaryOn(on, values);
393         return this;
394      }
395
396      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
397      public Builder disableBeansRequireSomeProperties() {
398         super.disableBeansRequireSomeProperties();
399         return this;
400      }
401
402      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
403      public Builder disableIgnoreMissingSetters() {
404         super.disableIgnoreMissingSetters();
405         return this;
406      }
407
408      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
409      public Builder disableIgnoreTransientFields() {
410         super.disableIgnoreTransientFields();
411         return this;
412      }
413
414      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
415      public Builder disableIgnoreUnknownNullBeanProperties() {
416         super.disableIgnoreUnknownNullBeanProperties();
417         return this;
418      }
419
420      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
421      public Builder disableInterfaceProxies() {
422         super.disableInterfaceProxies();
423         return this;
424      }
425
426      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
427      public <T> Builder example(Class<T> pojoClass, T o) {
428         super.example(pojoClass, o);
429         return this;
430      }
431
432      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
433      public <T> Builder example(Class<T> pojoClass, String json) {
434         super.example(pojoClass, json);
435         return this;
436      }
437
438      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
439      public Builder findFluentSetters() {
440         super.findFluentSetters();
441         return this;
442      }
443
444      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
445      public Builder findFluentSetters(Class<?> on) {
446         super.findFluentSetters(on);
447         return this;
448      }
449
450      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
451      public Builder ignoreInvocationExceptionsOnGetters() {
452         super.ignoreInvocationExceptionsOnGetters();
453         return this;
454      }
455
456      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
457      public Builder ignoreInvocationExceptionsOnSetters() {
458         super.ignoreInvocationExceptionsOnSetters();
459         return this;
460      }
461
462      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
463      public Builder ignoreUnknownBeanProperties() {
464         super.ignoreUnknownBeanProperties();
465         return this;
466      }
467
468      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
469      public Builder ignoreUnknownEnumValues() {
470         super.ignoreUnknownEnumValues();
471         return this;
472      }
473
474      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
475      public Builder implClass(Class<?> interfaceClass, Class<?> implClass) {
476         super.implClass(interfaceClass, implClass);
477         return this;
478      }
479
480      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
481      public Builder implClasses(Map<Class<?>,Class<?>> values) {
482         super.implClasses(values);
483         return this;
484      }
485
486      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
487      public Builder interfaceClass(Class<?> on, Class<?> value) {
488         super.interfaceClass(on, value);
489         return this;
490      }
491
492      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
493      public Builder interfaces(java.lang.Class<?>...value) {
494         super.interfaces(value);
495         return this;
496      }
497
498      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
499      public Builder locale(Locale value) {
500         super.locale(value);
501         return this;
502      }
503
504      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
505      public Builder mediaType(MediaType value) {
506         super.mediaType(value);
507         return this;
508      }
509
510      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
511      public Builder notBeanClasses(java.lang.Class<?>...values) {
512         super.notBeanClasses(values);
513         return this;
514      }
515
516      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
517      public Builder notBeanPackages(String...values) {
518         super.notBeanPackages(values);
519         return this;
520      }
521
522      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
523      public Builder propertyNamer(Class<? extends org.apache.juneau.PropertyNamer> value) {
524         super.propertyNamer(value);
525         return this;
526      }
527
528      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
529      public Builder propertyNamer(Class<?> on, Class<? extends org.apache.juneau.PropertyNamer> value) {
530         super.propertyNamer(on, value);
531         return this;
532      }
533
534      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
535      public Builder sortProperties() {
536         super.sortProperties();
537         return this;
538      }
539
540      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
541      public Builder sortProperties(java.lang.Class<?>...on) {
542         super.sortProperties(on);
543         return this;
544      }
545
546      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
547      public Builder stopClass(Class<?> on, Class<?> value) {
548         super.stopClass(on, value);
549         return this;
550      }
551
552      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
553      public <T, S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction) {
554         super.swap(normalClass, swappedClass, swapFunction);
555         return this;
556      }
557
558      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
559      public <T, S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction, ThrowingFunction<S,T> unswapFunction) {
560         super.swap(normalClass, swappedClass, swapFunction, unswapFunction);
561         return this;
562      }
563
564      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
565      public Builder swaps(java.lang.Class<?>...values) {
566         super.swaps(values);
567         return this;
568      }
569
570      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
571      public Builder timeZone(TimeZone value) {
572         super.timeZone(value);
573         return this;
574      }
575
576      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
577      public Builder typeName(Class<?> on, String value) {
578         super.typeName(on, value);
579         return this;
580      }
581
582      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
583      public Builder typePropertyName(String value) {
584         super.typePropertyName(value);
585         return this;
586      }
587
588      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
589      public Builder typePropertyName(Class<?> on, String value) {
590         super.typePropertyName(on, value);
591         return this;
592      }
593
594      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
595      public Builder useEnumNames() {
596         super.useEnumNames();
597         return this;
598      }
599
600      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
601      public Builder useJavaBeanIntrospector() {
602         super.useJavaBeanIntrospector();
603         return this;
604      }
605
606      @Override /* GENERATED - org.apache.juneau.parser.Parser.Builder */
607      public Builder autoCloseStreams() {
608         super.autoCloseStreams();
609         return this;
610      }
611
612      @Override /* GENERATED - org.apache.juneau.parser.Parser.Builder */
613      public Builder autoCloseStreams(boolean value) {
614         super.autoCloseStreams(value);
615         return this;
616      }
617
618      @Override /* GENERATED - org.apache.juneau.parser.Parser.Builder */
619      public Builder consumes(String value) {
620         super.consumes(value);
621         return this;
622      }
623
624      @Override /* GENERATED - org.apache.juneau.parser.Parser.Builder */
625      public Builder debugOutputLines(int value) {
626         super.debugOutputLines(value);
627         return this;
628      }
629
630      @Override /* GENERATED - org.apache.juneau.parser.Parser.Builder */
631      public Builder listener(Class<? extends org.apache.juneau.parser.ParserListener> value) {
632         super.listener(value);
633         return this;
634      }
635
636      @Override /* GENERATED - org.apache.juneau.parser.Parser.Builder */
637      public Builder strict() {
638         super.strict();
639         return this;
640      }
641
642      @Override /* GENERATED - org.apache.juneau.parser.Parser.Builder */
643      public Builder strict(boolean value) {
644         super.strict(value);
645         return this;
646      }
647
648      @Override /* GENERATED - org.apache.juneau.parser.Parser.Builder */
649      public Builder trimStrings() {
650         super.trimStrings();
651         return this;
652      }
653
654      @Override /* GENERATED - org.apache.juneau.parser.Parser.Builder */
655      public Builder trimStrings(boolean value) {
656         super.trimStrings(value);
657         return this;
658      }
659
660      @Override /* GENERATED - org.apache.juneau.parser.Parser.Builder */
661      public Builder unbuffered() {
662         super.unbuffered();
663         return this;
664      }
665
666      @Override /* GENERATED - org.apache.juneau.parser.Parser.Builder */
667      public Builder unbuffered(boolean value) {
668         super.unbuffered(value);
669         return this;
670      }
671
672      @Override /* GENERATED - org.apache.juneau.parser.ReaderParser.Builder */
673      public Builder fileCharset(Charset value) {
674         super.fileCharset(value);
675         return this;
676      }
677
678      @Override /* GENERATED - org.apache.juneau.parser.ReaderParser.Builder */
679      public Builder streamCharset(Charset value) {
680         super.streamCharset(value);
681         return this;
682      }
683
684      @Override /* GENERATED - org.apache.juneau.uon.UonParser.Builder */
685      public Builder decoding() {
686         super.decoding();
687         return this;
688      }
689
690      @Override /* GENERATED - org.apache.juneau.uon.UonParser.Builder */
691      public Builder decoding(boolean value) {
692         super.decoding(value);
693         return this;
694      }
695
696      @Override /* GENERATED - org.apache.juneau.uon.UonParser.Builder */
697      public Builder validateEnd() {
698         super.validateEnd();
699         return this;
700      }
701
702      @Override /* GENERATED - org.apache.juneau.uon.UonParser.Builder */
703      public Builder validateEnd(boolean value) {
704         super.validateEnd(value);
705         return this;
706      }
707
708      // </FluentSetters>
709   }
710
711   //-------------------------------------------------------------------------------------------------------------------
712   // Instance
713   //-------------------------------------------------------------------------------------------------------------------
714
715   final boolean expandedParams;
716
717   private final Map<ClassMeta<?>,UrlEncodingClassMeta> urlEncodingClassMetas = new ConcurrentHashMap<>();
718   private final Map<BeanPropertyMeta,UrlEncodingBeanPropertyMeta> urlEncodingBeanPropertyMetas = new ConcurrentHashMap<>();
719
720   /**
721    * Constructor.
722    *
723    * @param builder The builder for this object.
724    */
725   public UrlEncodingParser(Builder builder) {
726      super(builder);
727      expandedParams = builder.expandedParams;
728   }
729
730   @Override /* Context */
731   public Builder copy() {
732      return new Builder(this);
733   }
734
735   @Override /* Context */
736   public UrlEncodingParserSession.Builder createSession() {
737      return UrlEncodingParserSession.create(this);
738   }
739
740   @Override /* Context */
741   public UrlEncodingParserSession getSession() {
742      return createSession().build();
743   }
744
745   //-----------------------------------------------------------------------------------------------------------------
746   // Extended metadata
747   //-----------------------------------------------------------------------------------------------------------------
748
749   @Override /* UrlEncodingMetaProvider */
750   public UrlEncodingClassMeta getUrlEncodingClassMeta(ClassMeta<?> cm) {
751      UrlEncodingClassMeta m = urlEncodingClassMetas.get(cm);
752      if (m == null) {
753         m = new UrlEncodingClassMeta(cm, this);
754         urlEncodingClassMetas.put(cm, m);
755      }
756      return m;
757   }
758
759   @Override /* UrlEncodingMetaProvider */
760   public UrlEncodingBeanPropertyMeta getUrlEncodingBeanPropertyMeta(BeanPropertyMeta bpm) {
761      if (bpm == null)
762         return UrlEncodingBeanPropertyMeta.DEFAULT;
763      UrlEncodingBeanPropertyMeta m = urlEncodingBeanPropertyMetas.get(bpm);
764      if (m == null) {
765         m = new UrlEncodingBeanPropertyMeta(bpm.getDelegateFor(), this);
766         urlEncodingBeanPropertyMetas.put(bpm, m);
767      }
768      return m;
769   }
770
771   //-----------------------------------------------------------------------------------------------------------------
772   // Properties
773   //-----------------------------------------------------------------------------------------------------------------
774
775   /**
776    * Parser bean property collections/arrays as separate key/value pairs.
777    *
778    * @see Builder#expandedParams()
779    * @return
780    * <jk>false</jk> if serializing the array <c>[1,2,3]</c> results in <c>?key=$a(1,2,3)</c>.
781    * <br><jk>true</jk> if serializing the same array results in <c>?key=1&amp;key=2&amp;key=3</c>.
782    */
783   protected final boolean isExpandedParams() {
784      return expandedParams;
785   }
786
787   //-----------------------------------------------------------------------------------------------------------------
788   // Other methods
789   //-----------------------------------------------------------------------------------------------------------------
790
791   @Override /* Context */
792   protected JsonMap properties() {
793      return filteredMap("expandedParams", expandedParams);
794   }
795}