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