001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.uon;
014
015import static org.apache.juneau.collections.JsonMap.*;
016import java.lang.annotation.*;
017import java.lang.reflect.*;
018import java.nio.charset.*;
019import java.util.*;
020import java.util.concurrent.*;
021
022import org.apache.juneau.*;
023import org.apache.juneau.collections.*;
024import org.apache.juneau.httppart.*;
025import org.apache.juneau.internal.*;
026import org.apache.juneau.parser.*;
027import org.apache.juneau.utils.*;
028
029/**
030 * Parses UON (a notation for URL-encoded query parameter values) text into POJO models.
031 *
032 * <h5 class='topic'>Media types</h5>
033 * <p>
034 * Handles <c>Content-Type</c> types:  <bc>text/uon</bc>
035 *
036 * <h5 class='topic'>Description</h5>
037 * <p>
038 * This parser uses a state machine, which makes it very fast and efficient.
039 *
040 * <h5 class='section'>Notes:</h5><ul>
041 *    <li class='note'>This class is thread safe and reusable.
042 * </ul>
043 *
044 * <h5 class='section'>See Also:</h5><ul>
045 *    <li class='link'><a class="doclink" href="../../../../index.html#jm.UonDetails">UON Details</a>
046
047 * </ul>
048 */
049public class UonParser extends ReaderParser implements HttpPartParser, UonMetaProvider {
050
051   //-------------------------------------------------------------------------------------------------------------------
052   // Static
053   //-------------------------------------------------------------------------------------------------------------------
054
055   /** Reusable instance of {@link UonParser}, all default settings. */
056   public static final UonParser DEFAULT = new UonParser(create());
057
058   /** Reusable instance of {@link UonParser} with decodeChars set to true. */
059   public static final UonParser DEFAULT_DECODING = new UonParser.Decoding(create());
060
061   /**
062    * Creates a new builder for this object.
063    *
064    * @return A new builder.
065    */
066   public static Builder create() {
067      return new Builder();
068   }
069
070   //-------------------------------------------------------------------------------------------------------------------
071   // Static subclasses
072   //-------------------------------------------------------------------------------------------------------------------
073
074   /** Default parser, decoding. */
075   public static class Decoding extends UonParser {
076
077      /**
078       * Constructor.
079       *
080       * @param builder The builder for this object.
081       */
082      public Decoding(Builder builder) {
083         super(builder.decoding());
084      }
085   }
086
087   //-------------------------------------------------------------------------------------------------------------------
088   // Builder
089   //-------------------------------------------------------------------------------------------------------------------
090
091   /**
092    * Builder class.
093    */
094   @FluentSetters
095   public static class Builder extends ReaderParser.Builder {
096
097      private static final Cache<HashKey,UonParser> CACHE = Cache.of(HashKey.class, UonParser.class).build();
098
099      boolean decoding, validateEnd;
100
101      /**
102       * Constructor, default settings.
103       */
104      protected Builder() {
105         super();
106         consumes("text/uon");
107         decoding = env("UonParser.decoding", false);
108         validateEnd = env("UonParser.validateEnd", false);
109      }
110
111      /**
112       * Copy constructor.
113       *
114       * @param copyFrom The bean to copy from.
115       */
116      protected Builder(UonParser copyFrom) {
117         super(copyFrom);
118         decoding = copyFrom.decoding;
119         validateEnd = copyFrom.validateEnd;
120      }
121
122      /**
123       * Copy constructor.
124       *
125       * @param copyFrom The builder to copy from.
126       */
127      protected Builder(Builder copyFrom) {
128         super(copyFrom);
129         decoding = copyFrom.decoding;
130         validateEnd = copyFrom.validateEnd;
131      }
132
133      @Override /* Context.Builder */
134      public Builder copy() {
135         return new Builder(this);
136      }
137
138      @Override /* Context.Builder */
139      public UonParser build() {
140         return cache(CACHE).build(UonParser.class);
141      }
142
143      @Override /* Context.Builder */
144      public HashKey hashKey() {
145         return HashKey.of(
146            super.hashKey(),
147            decoding,
148            validateEnd
149         );
150      }
151
152      //-----------------------------------------------------------------------------------------------------------------
153      // Properties
154      //-----------------------------------------------------------------------------------------------------------------
155
156      /**
157       * Decode <js>"%xx"</js> sequences.
158       *
159       * <p>
160       * When enabled, URI encoded characters will be decoded.  Otherwise it's assumed that they've already been decoded
161       * before being passed to this parser.
162       *
163       * <h5 class='section'>Example:</h5>
164       * <p class='bjava'>
165       *    <jc>// Create a decoding UON parser.</jc>
166       *    ReaderParser <jv>parser</jv> = UonParser.
167       *       .<jsm>create</jsm>()
168       *       .decoding()
169       *       .build();
170       *
171       *  <jc>// Produces: ["foo bar", "baz quz"].</jc>
172       *    String[] <jv>foo</jv> = <jv>parser</jv>.parse(<js>"@(foo%20bar,baz%20qux)"</js>, String[].<jk>class</jk>);
173       * </p>
174       *
175       * @return This object.
176       */
177      @FluentSetter
178      public Builder decoding() {
179         return decoding(true);
180      }
181
182      /**
183       * Same as {@link #decoding()} but allows you to explicitly specify the value.
184       *
185       * @param value The value for this setting.
186       * @return This object.
187       */
188      @FluentSetter
189      public Builder decoding(boolean value) {
190         decoding = value;
191         return this;
192      }
193
194      /**
195       * Validate end.
196       *
197       * <p>
198       * When enabled, after parsing a POJO from the input, verifies that the remaining input in
199       * the stream consists of only comments or whitespace.
200       *
201       * <h5 class='section'>Example:</h5>
202       * <p class='bjava'>
203       *    <jc>// Create a parser using strict mode.</jc>
204       *    ReaderParser <jv>parser</jv> = UonParser.
205       *       .<jsm>create</jsm>()
206       *       .validateEnd()
207       *       .build();
208       *
209       *    <jc>// Should fail because input has multiple POJOs.</jc>
210       *    String <jv>in</jv> = <js>"(foo=bar)(baz=qux)"</js>;
211       *    MyBean <jv>myBean</jv> = <jv>parser</jv>.parse(<jv>in</jv>, MyBean.<jk>class</jk>);
212       * </p>
213       *
214       * @return This object.
215       */
216      @FluentSetter
217      public Builder validateEnd() {
218         return validateEnd(true);
219      }
220
221      /**
222       * Same as {@link #validateEnd()} but allows you to explicitly specify the value.
223       *
224       * @param value The value for this setting.
225       * @return This object.
226       */
227      @FluentSetter
228      public Builder validateEnd(boolean value) {
229         validateEnd = value;
230         return this;
231      }
232
233      // <FluentSetters>
234
235      @Override /* GENERATED - org.apache.juneau.Context.Builder */
236      public Builder annotations(Annotation...values) {
237         super.annotations(values);
238         return this;
239      }
240
241      @Override /* GENERATED - org.apache.juneau.Context.Builder */
242      public Builder apply(AnnotationWorkList work) {
243         super.apply(work);
244         return this;
245      }
246
247      @Override /* GENERATED - org.apache.juneau.Context.Builder */
248      public Builder applyAnnotations(java.lang.Class<?>...fromClasses) {
249         super.applyAnnotations(fromClasses);
250         return this;
251      }
252
253      @Override /* GENERATED - org.apache.juneau.Context.Builder */
254      public Builder applyAnnotations(Method...fromMethods) {
255         super.applyAnnotations(fromMethods);
256         return this;
257      }
258
259      @Override /* GENERATED - org.apache.juneau.Context.Builder */
260      public Builder cache(Cache<HashKey,? extends org.apache.juneau.Context> value) {
261         super.cache(value);
262         return this;
263      }
264
265      @Override /* GENERATED - org.apache.juneau.Context.Builder */
266      public Builder debug() {
267         super.debug();
268         return this;
269      }
270
271      @Override /* GENERATED - org.apache.juneau.Context.Builder */
272      public Builder debug(boolean value) {
273         super.debug(value);
274         return this;
275      }
276
277      @Override /* GENERATED - org.apache.juneau.Context.Builder */
278      public Builder impl(Context value) {
279         super.impl(value);
280         return this;
281      }
282
283      @Override /* GENERATED - org.apache.juneau.Context.Builder */
284      public Builder type(Class<? extends org.apache.juneau.Context> value) {
285         super.type(value);
286         return this;
287      }
288
289      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
290      public Builder beanClassVisibility(Visibility value) {
291         super.beanClassVisibility(value);
292         return this;
293      }
294
295      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
296      public Builder beanConstructorVisibility(Visibility value) {
297         super.beanConstructorVisibility(value);
298         return this;
299      }
300
301      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
302      public Builder beanContext(BeanContext value) {
303         super.beanContext(value);
304         return this;
305      }
306
307      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
308      public Builder beanContext(BeanContext.Builder value) {
309         super.beanContext(value);
310         return this;
311      }
312
313      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
314      public Builder beanDictionary(java.lang.Class<?>...values) {
315         super.beanDictionary(values);
316         return this;
317      }
318
319      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
320      public Builder beanFieldVisibility(Visibility value) {
321         super.beanFieldVisibility(value);
322         return this;
323      }
324
325      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
326      public Builder beanInterceptor(Class<?> on, Class<? extends org.apache.juneau.swap.BeanInterceptor<?>> value) {
327         super.beanInterceptor(on, value);
328         return this;
329      }
330
331      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
332      public Builder beanMapPutReturnsOldValue() {
333         super.beanMapPutReturnsOldValue();
334         return this;
335      }
336
337      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
338      public Builder beanMethodVisibility(Visibility value) {
339         super.beanMethodVisibility(value);
340         return this;
341      }
342
343      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
344      public Builder beanProperties(Map<String,Object> values) {
345         super.beanProperties(values);
346         return this;
347      }
348
349      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
350      public Builder beanProperties(Class<?> beanClass, String properties) {
351         super.beanProperties(beanClass, properties);
352         return this;
353      }
354
355      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
356      public Builder beanProperties(String beanClassName, String properties) {
357         super.beanProperties(beanClassName, properties);
358         return this;
359      }
360
361      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
362      public Builder beanPropertiesExcludes(Map<String,Object> values) {
363         super.beanPropertiesExcludes(values);
364         return this;
365      }
366
367      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
368      public Builder beanPropertiesExcludes(Class<?> beanClass, String properties) {
369         super.beanPropertiesExcludes(beanClass, properties);
370         return this;
371      }
372
373      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
374      public Builder beanPropertiesExcludes(String beanClassName, String properties) {
375         super.beanPropertiesExcludes(beanClassName, properties);
376         return this;
377      }
378
379      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
380      public Builder beanPropertiesReadOnly(Map<String,Object> values) {
381         super.beanPropertiesReadOnly(values);
382         return this;
383      }
384
385      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
386      public Builder beanPropertiesReadOnly(Class<?> beanClass, String properties) {
387         super.beanPropertiesReadOnly(beanClass, properties);
388         return this;
389      }
390
391      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
392      public Builder beanPropertiesReadOnly(String beanClassName, String properties) {
393         super.beanPropertiesReadOnly(beanClassName, properties);
394         return this;
395      }
396
397      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
398      public Builder beanPropertiesWriteOnly(Map<String,Object> values) {
399         super.beanPropertiesWriteOnly(values);
400         return this;
401      }
402
403      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
404      public Builder beanPropertiesWriteOnly(Class<?> beanClass, String properties) {
405         super.beanPropertiesWriteOnly(beanClass, properties);
406         return this;
407      }
408
409      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
410      public Builder beanPropertiesWriteOnly(String beanClassName, String properties) {
411         super.beanPropertiesWriteOnly(beanClassName, properties);
412         return this;
413      }
414
415      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
416      public Builder beansRequireDefaultConstructor() {
417         super.beansRequireDefaultConstructor();
418         return this;
419      }
420
421      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
422      public Builder beansRequireSerializable() {
423         super.beansRequireSerializable();
424         return this;
425      }
426
427      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
428      public Builder beansRequireSettersForGetters() {
429         super.beansRequireSettersForGetters();
430         return this;
431      }
432
433      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
434      public Builder dictionaryOn(Class<?> on, java.lang.Class<?>...values) {
435         super.dictionaryOn(on, values);
436         return this;
437      }
438
439      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
440      public Builder disableBeansRequireSomeProperties() {
441         super.disableBeansRequireSomeProperties();
442         return this;
443      }
444
445      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
446      public Builder disableIgnoreMissingSetters() {
447         super.disableIgnoreMissingSetters();
448         return this;
449      }
450
451      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
452      public Builder disableIgnoreTransientFields() {
453         super.disableIgnoreTransientFields();
454         return this;
455      }
456
457      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
458      public Builder disableIgnoreUnknownNullBeanProperties() {
459         super.disableIgnoreUnknownNullBeanProperties();
460         return this;
461      }
462
463      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
464      public Builder disableInterfaceProxies() {
465         super.disableInterfaceProxies();
466         return this;
467      }
468
469      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
470      public <T> Builder example(Class<T> pojoClass, T o) {
471         super.example(pojoClass, o);
472         return this;
473      }
474
475      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
476      public <T> Builder example(Class<T> pojoClass, String json) {
477         super.example(pojoClass, json);
478         return this;
479      }
480
481      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
482      public Builder findFluentSetters() {
483         super.findFluentSetters();
484         return this;
485      }
486
487      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
488      public Builder findFluentSetters(Class<?> on) {
489         super.findFluentSetters(on);
490         return this;
491      }
492
493      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
494      public Builder ignoreInvocationExceptionsOnGetters() {
495         super.ignoreInvocationExceptionsOnGetters();
496         return this;
497      }
498
499      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
500      public Builder ignoreInvocationExceptionsOnSetters() {
501         super.ignoreInvocationExceptionsOnSetters();
502         return this;
503      }
504
505      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
506      public Builder ignoreUnknownBeanProperties() {
507         super.ignoreUnknownBeanProperties();
508         return this;
509      }
510
511      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
512      public Builder ignoreUnknownEnumValues() {
513         super.ignoreUnknownEnumValues();
514         return this;
515      }
516
517      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
518      public Builder implClass(Class<?> interfaceClass, Class<?> implClass) {
519         super.implClass(interfaceClass, implClass);
520         return this;
521      }
522
523      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
524      public Builder implClasses(Map<Class<?>,Class<?>> values) {
525         super.implClasses(values);
526         return this;
527      }
528
529      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
530      public Builder interfaceClass(Class<?> on, Class<?> value) {
531         super.interfaceClass(on, value);
532         return this;
533      }
534
535      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
536      public Builder interfaces(java.lang.Class<?>...value) {
537         super.interfaces(value);
538         return this;
539      }
540
541      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
542      public Builder locale(Locale value) {
543         super.locale(value);
544         return this;
545      }
546
547      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
548      public Builder mediaType(MediaType value) {
549         super.mediaType(value);
550         return this;
551      }
552
553      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
554      public Builder notBeanClasses(java.lang.Class<?>...values) {
555         super.notBeanClasses(values);
556         return this;
557      }
558
559      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
560      public Builder notBeanPackages(String...values) {
561         super.notBeanPackages(values);
562         return this;
563      }
564
565      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
566      public Builder propertyNamer(Class<? extends org.apache.juneau.PropertyNamer> value) {
567         super.propertyNamer(value);
568         return this;
569      }
570
571      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
572      public Builder propertyNamer(Class<?> on, Class<? extends org.apache.juneau.PropertyNamer> value) {
573         super.propertyNamer(on, value);
574         return this;
575      }
576
577      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
578      public Builder sortProperties() {
579         super.sortProperties();
580         return this;
581      }
582
583      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
584      public Builder sortProperties(java.lang.Class<?>...on) {
585         super.sortProperties(on);
586         return this;
587      }
588
589      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
590      public Builder stopClass(Class<?> on, Class<?> value) {
591         super.stopClass(on, value);
592         return this;
593      }
594
595      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
596      public <T, S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction) {
597         super.swap(normalClass, swappedClass, swapFunction);
598         return this;
599      }
600
601      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
602      public <T, S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction, ThrowingFunction<S,T> unswapFunction) {
603         super.swap(normalClass, swappedClass, swapFunction, unswapFunction);
604         return this;
605      }
606
607      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
608      public Builder swaps(java.lang.Class<?>...values) {
609         super.swaps(values);
610         return this;
611      }
612
613      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
614      public Builder timeZone(TimeZone value) {
615         super.timeZone(value);
616         return this;
617      }
618
619      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
620      public Builder typeName(Class<?> on, String value) {
621         super.typeName(on, value);
622         return this;
623      }
624
625      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
626      public Builder typePropertyName(String value) {
627         super.typePropertyName(value);
628         return this;
629      }
630
631      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
632      public Builder typePropertyName(Class<?> on, String value) {
633         super.typePropertyName(on, value);
634         return this;
635      }
636
637      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
638      public Builder useEnumNames() {
639         super.useEnumNames();
640         return this;
641      }
642
643      @Override /* GENERATED - org.apache.juneau.BeanContextable.Builder */
644      public Builder useJavaBeanIntrospector() {
645         super.useJavaBeanIntrospector();
646         return this;
647      }
648
649      @Override /* GENERATED - org.apache.juneau.parser.Parser.Builder */
650      public Builder autoCloseStreams() {
651         super.autoCloseStreams();
652         return this;
653      }
654
655      @Override /* GENERATED - org.apache.juneau.parser.Parser.Builder */
656      public Builder autoCloseStreams(boolean value) {
657         super.autoCloseStreams(value);
658         return this;
659      }
660
661      @Override /* GENERATED - org.apache.juneau.parser.Parser.Builder */
662      public Builder consumes(String value) {
663         super.consumes(value);
664         return this;
665      }
666
667      @Override /* GENERATED - org.apache.juneau.parser.Parser.Builder */
668      public Builder debugOutputLines(int value) {
669         super.debugOutputLines(value);
670         return this;
671      }
672
673      @Override /* GENERATED - org.apache.juneau.parser.Parser.Builder */
674      public Builder listener(Class<? extends org.apache.juneau.parser.ParserListener> value) {
675         super.listener(value);
676         return this;
677      }
678
679      @Override /* GENERATED - org.apache.juneau.parser.Parser.Builder */
680      public Builder strict() {
681         super.strict();
682         return this;
683      }
684
685      @Override /* GENERATED - org.apache.juneau.parser.Parser.Builder */
686      public Builder strict(boolean value) {
687         super.strict(value);
688         return this;
689      }
690
691      @Override /* GENERATED - org.apache.juneau.parser.Parser.Builder */
692      public Builder trimStrings() {
693         super.trimStrings();
694         return this;
695      }
696
697      @Override /* GENERATED - org.apache.juneau.parser.Parser.Builder */
698      public Builder trimStrings(boolean value) {
699         super.trimStrings(value);
700         return this;
701      }
702
703      @Override /* GENERATED - org.apache.juneau.parser.Parser.Builder */
704      public Builder unbuffered() {
705         super.unbuffered();
706         return this;
707      }
708
709      @Override /* GENERATED - org.apache.juneau.parser.Parser.Builder */
710      public Builder unbuffered(boolean value) {
711         super.unbuffered(value);
712         return this;
713      }
714
715      @Override /* GENERATED - org.apache.juneau.parser.ReaderParser.Builder */
716      public Builder fileCharset(Charset value) {
717         super.fileCharset(value);
718         return this;
719      }
720
721      @Override /* GENERATED - org.apache.juneau.parser.ReaderParser.Builder */
722      public Builder streamCharset(Charset value) {
723         super.streamCharset(value);
724         return this;
725      }
726
727      // </FluentSetters>
728   }
729
730   //-------------------------------------------------------------------------------------------------------------------
731   // Instance
732   //-------------------------------------------------------------------------------------------------------------------
733
734   final boolean decoding, validateEnd;
735
736   private final Map<ClassMeta<?>,UonClassMeta> uonClassMetas = new ConcurrentHashMap<>();
737   private final Map<BeanPropertyMeta,UonBeanPropertyMeta> uonBeanPropertyMetas = new ConcurrentHashMap<>();
738
739   /**
740    * Constructor.
741    *
742    * @param builder The builder for this object.
743    */
744   public UonParser(Builder builder) {
745      super(builder);
746      decoding = builder.decoding;
747      validateEnd = builder.validateEnd;
748   }
749
750   @Override /* Context */
751   public Builder copy() {
752      return new Builder(this);
753   }
754
755   @Override /* Context */
756   public UonParserSession.Builder createSession() {
757      return UonParserSession.create(this);
758   }
759
760   @Override /* Context */
761   public UonParserSession getSession() {
762      return createSession().build();
763   }
764
765   @Override /* HttpPartParser */
766   public UonParserSession getPartSession() {
767      return UonParserSession.create(this).build();
768   }
769
770   /**
771    * Converts the specified input to the specified class type.
772    *
773    * @param <T> The POJO type to transform the input into.
774    * @param partType The part type being parsed.
775    * @param schema
776    *    Schema information about the part.
777    *    <br>May be <jk>null</jk>.
778    *    <br>Not all part parsers use the schema information.
779    * @param in The input being parsed.
780    * @param toType The POJO type to transform the input into.
781    * @return The parsed value.
782    * @throws ParseException Malformed input encountered.
783    * @throws SchemaValidationException If the input or resulting HTTP part object fails schema validation.
784    */
785   public <T> T parse(HttpPartType partType, HttpPartSchema schema, String in, ClassMeta<T> toType) throws ParseException, SchemaValidationException {
786      return getPartSession().parse(partType, schema, in, toType);
787   }
788
789   /**
790    * Converts the specified input to the specified class type.
791    *
792    * @param <T> The POJO type to transform the input into.
793    * @param partType The part type being parsed.
794    * @param schema
795    *    Schema information about the part.
796    *    <br>May be <jk>null</jk>.
797    *    <br>Not all part parsers use the schema information.
798    * @param in The input being parsed.
799    * @param toType The POJO type to transform the input into.
800    * @return The parsed value.
801    * @throws ParseException Malformed input encountered.
802    * @throws SchemaValidationException If the input or resulting HTTP part object fails schema validation.
803    */
804   public <T> T parse(HttpPartType partType, HttpPartSchema schema, String in, Class<T> toType) throws ParseException, SchemaValidationException {
805      return getPartSession().parse(partType, schema, in, getClassMeta(toType));
806   }
807
808   /**
809    * Converts the specified input to the specified class type.
810    *
811    * @param <T> The POJO type to transform the input into.
812    * @param partType The part type being parsed.
813    * @param schema
814    *    Schema information about the part.
815    *    <br>May be <jk>null</jk>.
816    *    <br>Not all part parsers use the schema information.
817    * @param in The input being parsed.
818    * @param toType The POJO type to transform the input into.
819    * @param toTypeArgs The generic type arguments of the POJO type to transform the input into.
820    * @return The parsed value.
821    * @throws ParseException Malformed input encountered.
822    * @throws SchemaValidationException If the input or resulting HTTP part object fails schema validation.
823    */
824   public <T> T parse(HttpPartType partType, HttpPartSchema schema, String in, Type toType, Type...toTypeArgs) throws ParseException, SchemaValidationException {
825      return getPartSession().parse(partType, schema, in, getClassMeta(toType, toTypeArgs));
826   }
827
828   //-----------------------------------------------------------------------------------------------------------------
829   // Extended metadata
830   //-----------------------------------------------------------------------------------------------------------------
831
832   @Override /* UonMetaProvider */
833   public UonClassMeta getUonClassMeta(ClassMeta<?> cm) {
834      UonClassMeta m = uonClassMetas.get(cm);
835      if (m == null) {
836         m = new UonClassMeta(cm, this);
837         uonClassMetas.put(cm, m);
838      }
839      return m;
840   }
841
842   @Override /* UonMetaProvider */
843   public UonBeanPropertyMeta getUonBeanPropertyMeta(BeanPropertyMeta bpm) {
844      if (bpm == null)
845         return UonBeanPropertyMeta.DEFAULT;
846      UonBeanPropertyMeta m = uonBeanPropertyMetas.get(bpm);
847      if (m == null) {
848         m = new UonBeanPropertyMeta(bpm.getDelegateFor(), this);
849         uonBeanPropertyMetas.put(bpm, m);
850      }
851      return m;
852   }
853
854   //-----------------------------------------------------------------------------------------------------------------
855   // Properties
856   //-----------------------------------------------------------------------------------------------------------------
857
858   /**
859    * Decode <js>"%xx"</js> sequences enabled
860    *
861    * @see Builder#decoding()
862    * @return
863    *    <jk>true</jk> if URI encoded characters should be decoded, <jk>false</jk> if they've already been decoded
864    *    before being passed to this parser.
865    */
866   protected final boolean isDecoding() {
867      return decoding;
868   }
869
870   /**
871    * Validate end enabled.
872    *
873    * @see Builder#validateEnd()
874    * @return
875    *    <jk>true</jk> if after parsing a POJO from the input, verifies that the remaining input in
876    *    the stream consists of only comments or whitespace.
877    */
878   protected final boolean isValidateEnd() {
879      return validateEnd;
880   }
881
882   //-----------------------------------------------------------------------------------------------------------------
883   // Other methods
884   //-----------------------------------------------------------------------------------------------------------------
885
886   @Override
887   public <T> ClassMeta<T> getClassMeta(Class<T> c) {
888      return getBeanContext().getClassMeta(c);
889   }
890
891   @Override
892   public <T> ClassMeta<T> getClassMeta(Type t, Type... args) {
893      return getBeanContext().getClassMeta(t, args);
894   }
895
896   @Override /* Context */
897   protected JsonMap properties() {
898      return filteredMap("decoding", decoding, "validateEnd", validateEnd);
899   }
900}