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