1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.juneau.parser;
18
19 import static org.apache.juneau.commons.utils.CollectionUtils.*;
20 import static org.apache.juneau.commons.utils.StringUtils.*;
21 import static org.apache.juneau.commons.utils.ThrowableUtils.*;
22 import static org.apache.juneau.commons.utils.Utils.*;
23
24 import java.io.*;
25 import java.lang.annotation.*;
26 import java.lang.reflect.*;
27 import java.nio.charset.*;
28 import java.util.*;
29
30 import org.apache.juneau.*;
31 import org.apache.juneau.collections.*;
32 import org.apache.juneau.commons.collections.*;
33 import org.apache.juneau.commons.function.*;
34 import org.apache.juneau.commons.reflect.*;
35 import org.apache.juneau.html.*;
36 import org.apache.juneau.json.*;
37 import org.apache.juneau.msgpack.*;
38 import org.apache.juneau.objecttools.*;
39 import org.apache.juneau.swap.*;
40 import org.apache.juneau.swaps.*;
41 import org.apache.juneau.uon.*;
42 import org.apache.juneau.xml.*;
43
44 /**
45 * Parent class for all Juneau parsers.
46 *
47 * <h5 class='topic'>Valid data conversions</h5>
48 * <p>
49 * Parsers can parse any parsable POJO types, as specified in the <a class="doclink" href="https://juneau.apache.org/docs/topics/PojoCategories">POJO Categories</a>.
50 *
51 * <p>
52 * Some examples of conversions are shown below...
53 * </p>
54 * <table class='styled'>
55 * <tr>
56 * <th>Data type</th>
57 * <th>Class type</th>
58 * <th>JSON example</th>
59 * <th>XML example</th>
60 * <th>Class examples</th>
61 * </tr>
62 * <tr>
63 * <td>object</td>
64 * <td>Maps, Java beans</td>
65 * <td class='code'>{name:<js>'John Smith'</js>,age:21}</td>
66 * <td class='code'><xt><object>
67 * <name</xt> <xa>type</xa>=<xs>'string'</xs><xt>></xt>John Smith<xt></name>
68 * <age</xt> <xa>type</xa>=<xs>'number'</xs><xt>></xt>21<xt></age>
69 * </object></xt></td>
70 * <td class='code'>HashMap, TreeMap<String,Integer></td>
71 * </tr>
72 * <tr>
73 * <td>array</td>
74 * <td>Collections, Java arrays</td>
75 * <td class='code'>[1,2,3]</td>
76 * <td class='code'><xt><array>
77 * <number></xt>1<xt></number>
78 * <number></xt>2<xt></number>
79 * <number></xt>3<xt></number>
80 * </array></xt></td>
81 * <td class='code'>List<Integer>, <jk>int</jk>[], Float[], Set<Person></td>
82 * </tr>
83 * <tr>
84 * <td>number</td>
85 * <td>Numbers</td>
86 * <td class='code'>123</td>
87 * <td class='code'><xt><number></xt>123<xt></number></xt></td>
88 * <td class='code'>Integer, Long, Float, <jk>int</jk></td>
89 * </tr>
90 * <tr>
91 * <td>boolean</td>
92 * <td>Booleans</td>
93 * <td class='code'><jk>true</jk></td>
94 * <td class='code'><xt><boolean></xt>true<xt></boolean></xt></td>
95 * <td class='code'>Boolean</td>
96 * </tr>
97 * <tr>
98 * <td>string</td>
99 * <td>CharSequences</td>
100 * <td class='code'><js>'foobar'</js></td>
101 * <td class='code'><xt><string></xt>foobar<xt></string></xt></td>
102 * <td class='code'>String, StringBuilder</td>
103 * </tr>
104 * </table>
105 *
106 * <p>
107 * In addition, any class types with {@link ObjectSwap ObjectSwaps} associated with them on the registered
108 * bean context can also be passed in.
109 *
110 * <p>
111 * For example, if the {@link TemporalCalendarSwap} transform is used to generalize {@code Calendar} objects to {@code String}
112 * objects.
113 * When registered with this parser, you can construct {@code Calendar} objects from {@code Strings} using the
114 * following syntax...
115 * <p class='bjava'>
116 * Calendar <jv>calendar</jv> = <jv>parser</jv>.parse(<js>"'Sun Mar 03 04:05:06 EST 2001'"</js>, GregorianCalendar.<jk>class</jk>);
117 * </p>
118 *
119 * <p>
120 * If <code>Object.<jk>class</jk></code> is specified as the target type, then the parser automatically determines the
121 * data types and generates the following object types...
122 * <table class='styled'>
123 * <tr><th>JSON type</th><th>Class type</th></tr>
124 * <tr><td>object</td><td>{@link JsonMap}</td></tr>
125 * <tr><td>array</td><td>{@link JsonList}</td></tr>
126 * <tr><td>number</td><td>{@link Number}<br>(depending on length and format, could be {@link Integer},
127 * {@link Double}, {@link Float}, etc...)</td></tr>
128 * <tr><td>boolean</td><td>{@link Boolean}</td></tr>
129 * <tr><td>string</td><td>{@link String}</td></tr>
130 * </table>
131 *
132 * <h5 class='section'>Notes:</h5><ul>
133 * <li class='note'>This class is thread safe and reusable.
134 * </ul>
135 *
136 * <h5 class='section'>See Also:</h5><ul>
137 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/SerializersAndParsers">Serializers and Parsers</a>
138
139 * </ul>
140 */
141 public class Parser extends BeanContextable {
142 /**
143 * Builder class.
144 */
145 public static class Builder extends BeanContextable.Builder {
146
147 private boolean autoCloseStreams;
148 private boolean strict;
149 private boolean trimStrings;
150 private boolean unbuffered;
151 private Class<? extends ParserListener> listener;
152 private int debugOutputLines;
153 private String consumes;
154
155 /**
156 * Constructor, default settings.
157 */
158 protected Builder() {
159 autoCloseStreams = env("Parser.autoCloseStreams", false);
160 strict = env("Parser.strict", false);
161 trimStrings = env("Parser.trimStrings", false);
162 unbuffered = env("Parser.unbuffered", false);
163 debugOutputLines = env("Parser.debugOutputLines", 5);
164 listener = null;
165 consumes = null;
166 }
167
168 /**
169 * Copy constructor.
170 *
171 * @param copyFrom The builder to copy from.
172 */
173 protected Builder(Builder copyFrom) {
174 super(copyFrom);
175 autoCloseStreams = copyFrom.autoCloseStreams;
176 strict = copyFrom.strict;
177 trimStrings = copyFrom.trimStrings;
178 unbuffered = copyFrom.unbuffered;
179 debugOutputLines = copyFrom.debugOutputLines;
180 listener = copyFrom.listener;
181 consumes = copyFrom.consumes;
182 }
183
184 /**
185 * Copy constructor.
186 *
187 * @param copyFrom The bean to copy from.
188 */
189 protected Builder(Parser copyFrom) {
190 super(copyFrom);
191 autoCloseStreams = copyFrom.autoCloseStreams;
192 strict = copyFrom.strict;
193 trimStrings = copyFrom.trimStrings;
194 unbuffered = copyFrom.unbuffered;
195 debugOutputLines = copyFrom.debugOutputLines;
196 listener = copyFrom.listener;
197 consumes = copyFrom.consumes;
198 }
199
200 @Override /* Overridden from Builder */
201 public Builder annotations(Annotation...values) {
202 super.annotations(values);
203 return this;
204 }
205
206 @Override /* Overridden from Builder */
207 public Builder apply(AnnotationWorkList work) {
208 super.apply(work);
209 return this;
210 }
211
212 @Override /* Overridden from Builder */
213 public Builder applyAnnotations(Class<?>...from) {
214 super.applyAnnotations(from);
215 return this;
216 }
217
218 @Override /* Overridden from Builder */
219 public Builder applyAnnotations(Object...from) {
220 super.applyAnnotations(from);
221 return this;
222 }
223
224 /**
225 * Auto-close streams.
226 *
227 * <p>
228 * When enabled, <l>InputStreams</l> and <l>Readers</l> passed into parsers will be closed
229 * after parsing is complete.
230 *
231 * <h5 class='section'>Example:</h5>
232 * <p class='bjava'>
233 * <jc>// Create a parser using strict mode.</jc>
234 * ReaderParser <jv>parser</jv> = JsonParser
235 * .<jsm>create</jsm>()
236 * .autoCloseStreams()
237 * .build();
238 *
239 * Reader <jv>myReader</jv> = <jk>new</jk> FileReader(<js>"/tmp/myfile.json"</js>);
240 * MyBean <jv>myBean</jv> = <jv>parser</jv>.parse(<jv>myReader</jv>, MyBean.<jk>class</jk>);
241 *
242 * <jsm>assertTrue</jsm>(<jv>myReader</jv>.isClosed());
243 * </p>
244 *
245 * @return This object.
246 */
247 public Builder autoCloseStreams() {
248 return autoCloseStreams(true);
249 }
250
251 /**
252 * Same as {@link #autoCloseStreams()} but allows you to explicitly specify the value.
253 *
254 * @param value The value for this setting.
255 * @return This object.
256 */
257 public Builder autoCloseStreams(boolean value) {
258 autoCloseStreams = value;
259 return this;
260 }
261
262 @Override /* Overridden from Builder */
263 public Builder beanClassVisibility(Visibility value) {
264 super.beanClassVisibility(value);
265 return this;
266 }
267
268 @Override /* Overridden from Builder */
269 public Builder beanConstructorVisibility(Visibility value) {
270 super.beanConstructorVisibility(value);
271 return this;
272 }
273
274 @Override /* Overridden from Builder */
275 public Builder beanContext(BeanContext value) {
276 super.beanContext(value);
277 return this;
278 }
279
280 @Override /* Overridden from Builder */
281 public Builder beanContext(BeanContext.Builder value) {
282 super.beanContext(value);
283 return this;
284 }
285
286 @Override /* Overridden from Builder */
287 public Builder beanDictionary(java.lang.Class<?>...values) {
288 super.beanDictionary(values);
289 return this;
290 }
291
292 @Override /* Overridden from Builder */
293 public Builder beanFieldVisibility(Visibility value) {
294 super.beanFieldVisibility(value);
295 return this;
296 }
297
298 @Override /* Overridden from Builder */
299 public Builder beanInterceptor(Class<?> on, Class<? extends org.apache.juneau.swap.BeanInterceptor<?>> value) {
300 super.beanInterceptor(on, value);
301 return this;
302 }
303
304 @Override /* Overridden from Builder */
305 public Builder beanMapPutReturnsOldValue() {
306 super.beanMapPutReturnsOldValue();
307 return this;
308 }
309
310 @Override /* Overridden from Builder */
311 public Builder beanMethodVisibility(Visibility value) {
312 super.beanMethodVisibility(value);
313 return this;
314 }
315
316 @Override /* Overridden from Builder */
317 public Builder beanProperties(Class<?> beanClass, String properties) {
318 super.beanProperties(beanClass, properties);
319 return this;
320 }
321
322 @Override /* Overridden from Builder */
323 public Builder beanProperties(Map<String,Object> values) {
324 super.beanProperties(values);
325 return this;
326 }
327
328 @Override /* Overridden from Builder */
329 public Builder beanProperties(String beanClassName, String properties) {
330 super.beanProperties(beanClassName, properties);
331 return this;
332 }
333
334 @Override /* Overridden from Builder */
335 public Builder beanPropertiesExcludes(Class<?> beanClass, String properties) {
336 super.beanPropertiesExcludes(beanClass, properties);
337 return this;
338 }
339
340 @Override /* Overridden from Builder */
341 public Builder beanPropertiesExcludes(Map<String,Object> values) {
342 super.beanPropertiesExcludes(values);
343 return this;
344 }
345
346 @Override /* Overridden from Builder */
347 public Builder beanPropertiesExcludes(String beanClassName, String properties) {
348 super.beanPropertiesExcludes(beanClassName, properties);
349 return this;
350 }
351
352 @Override /* Overridden from Builder */
353 public Builder beanPropertiesReadOnly(Class<?> beanClass, String properties) {
354 super.beanPropertiesReadOnly(beanClass, properties);
355 return this;
356 }
357
358 @Override /* Overridden from Builder */
359 public Builder beanPropertiesReadOnly(Map<String,Object> values) {
360 super.beanPropertiesReadOnly(values);
361 return this;
362 }
363
364 @Override /* Overridden from Builder */
365 public Builder beanPropertiesReadOnly(String beanClassName, String properties) {
366 super.beanPropertiesReadOnly(beanClassName, properties);
367 return this;
368 }
369
370 @Override /* Overridden from Builder */
371 public Builder beanPropertiesWriteOnly(Class<?> beanClass, String properties) {
372 super.beanPropertiesWriteOnly(beanClass, properties);
373 return this;
374 }
375
376 @Override /* Overridden from Builder */
377 public Builder beanPropertiesWriteOnly(Map<String,Object> values) {
378 super.beanPropertiesWriteOnly(values);
379 return this;
380 }
381
382 @Override /* Overridden from Builder */
383 public Builder beanPropertiesWriteOnly(String beanClassName, String properties) {
384 super.beanPropertiesWriteOnly(beanClassName, properties);
385 return this;
386 }
387
388 @Override /* Overridden from Builder */
389 public Builder beansRequireDefaultConstructor() {
390 super.beansRequireDefaultConstructor();
391 return this;
392 }
393
394 @Override /* Overridden from Builder */
395 public Builder beansRequireSerializable() {
396 super.beansRequireSerializable();
397 return this;
398 }
399
400 @Override /* Overridden from Builder */
401 public Builder beansRequireSettersForGetters() {
402 super.beansRequireSettersForGetters();
403 return this;
404 }
405
406 @Override /* Overridden from Context.Builder */
407 public Parser build() {
408 return build(Parser.class);
409 }
410
411 @Override /* Overridden from Builder */
412 public Builder cache(Cache<HashKey,? extends org.apache.juneau.Context> value) {
413 super.cache(value);
414 return this;
415 }
416
417 /**
418 * Specifies the media type that this parser consumes.
419 *
420 * @param value The value for this setting.
421 * <br>Can be <jk>null</jk> (treated as empty string, no media types will be specified).
422 * @return This object.
423 */
424 public Builder consumes(String value) {
425 consumes = value;
426 return this;
427 }
428
429 @Override /* Overridden from Context.Builder */
430 public Builder copy() {
431 return new Builder(this);
432 }
433
434 @Override /* Overridden from Builder */
435 public Builder debug() {
436 super.debug();
437 return this;
438 }
439
440 @Override /* Overridden from Builder */
441 public Builder debug(boolean value) {
442 super.debug(value);
443 return this;
444 }
445
446 /**
447 * Debug output lines.
448 *
449 * <p>
450 * When parse errors occur, this specifies the number of lines of input before and after the
451 * error location to be printed as part of the exception message.
452 *
453 * <h5 class='section'>Example:</h5>
454 * <p class='bjava'>
455 * <jc>// Create a parser whose exceptions print out 100 lines before and after the parse error location.</jc>
456 * ReaderParser <jv>parser</jv> = JsonParser
457 * .<jsm>create</jsm>()
458 * .debug() <jc>// Enable debug mode to capture Reader contents as strings.</jc>
459 * .debugOuputLines(100)
460 * .build();
461 *
462 * Reader <jv>myReader</jv> = <jk>new</jk> FileReader(<js>"/tmp/mybadfile.json"</js>);
463 * <jk>try</jk> {
464 * <jv>parser</jv>.parse(<jv>myReader</jv>, Object.<jk>class</jk>);
465 * } <jk>catch</jk> (ParseException <jv>e</jv>) {
466 * System.<jsf>err</jsf>.println(<jv>e</jv>.getMessage()); <jc>// Will display 200 lines of the output.</jc>
467 * }
468 * </p>
469 *
470 * @param value
471 * The new value for this property.
472 * <br>The default value is <c>5</c>.
473 * @return This object.
474 */
475 public Builder debugOutputLines(int value) {
476 debugOutputLines = value;
477 return this;
478 }
479
480 @Override /* Overridden from Builder */
481 public Builder dictionaryOn(Class<?> on, java.lang.Class<?>...values) {
482 super.dictionaryOn(on, values);
483 return this;
484 }
485
486 @Override /* Overridden from Builder */
487 public Builder disableBeansRequireSomeProperties() {
488 super.disableBeansRequireSomeProperties();
489 return this;
490 }
491
492 @Override /* Overridden from Builder */
493 public Builder disableIgnoreMissingSetters() {
494 super.disableIgnoreMissingSetters();
495 return this;
496 }
497
498 @Override /* Overridden from Builder */
499 public Builder disableIgnoreTransientFields() {
500 super.disableIgnoreTransientFields();
501 return this;
502 }
503
504 @Override /* Overridden from Builder */
505 public Builder disableIgnoreUnknownNullBeanProperties() {
506 super.disableIgnoreUnknownNullBeanProperties();
507 return this;
508 }
509
510 @Override /* Overridden from Builder */
511 public Builder disableInterfaceProxies() {
512 super.disableInterfaceProxies();
513 return this;
514 }
515
516 @Override /* Overridden from Builder */
517 public <T> Builder example(Class<T> pojoClass, String json) {
518 super.example(pojoClass, json);
519 return this;
520 }
521
522 @Override /* Overridden from Builder */
523 public <T> Builder example(Class<T> pojoClass, T o) {
524 super.example(pojoClass, o);
525 return this;
526 }
527
528 @Override /* Overridden from Builder */
529 public Builder findFluentSetters() {
530 super.findFluentSetters();
531 return this;
532 }
533
534 @Override /* Overridden from Builder */
535 public Builder findFluentSetters(Class<?> on) {
536 super.findFluentSetters(on);
537 return this;
538 }
539
540 /**
541 * Returns the current value for the 'consumes' property.
542 *
543 * @return The current value for the 'consumes' property.
544 */
545 public String getConsumes() { return consumes; }
546
547 @Override /* Overridden from Context.Builder */
548 public HashKey hashKey() {
549 // @formatter:off
550 return HashKey.of(
551 super.hashKey(),
552 autoCloseStreams,
553 strict,
554 trimStrings,
555 unbuffered,
556 debugOutputLines,
557 listener,
558 consumes
559 );
560 // @formatter:on
561 }
562
563 @Override /* Overridden from Builder */
564 public Builder ignoreInvocationExceptionsOnGetters() {
565 super.ignoreInvocationExceptionsOnGetters();
566 return this;
567 }
568
569 @Override /* Overridden from Builder */
570 public Builder ignoreInvocationExceptionsOnSetters() {
571 super.ignoreInvocationExceptionsOnSetters();
572 return this;
573 }
574
575 @Override /* Overridden from Builder */
576 public Builder ignoreUnknownBeanProperties() {
577 super.ignoreUnknownBeanProperties();
578 return this;
579 }
580
581 @Override /* Overridden from Builder */
582 public Builder ignoreUnknownEnumValues() {
583 super.ignoreUnknownEnumValues();
584 return this;
585 }
586
587 @Override /* Overridden from Builder */
588 public Builder impl(Context value) {
589 super.impl(value);
590 return this;
591 }
592
593 @Override /* Overridden from Builder */
594 public Builder implClass(Class<?> interfaceClass, Class<?> implClass) {
595 super.implClass(interfaceClass, implClass);
596 return this;
597 }
598
599 @Override /* Overridden from Builder */
600 public Builder implClasses(Map<Class<?>,Class<?>> values) {
601 super.implClasses(values);
602 return this;
603 }
604
605 @Override /* Overridden from Builder */
606 public Builder interfaceClass(Class<?> on, Class<?> value) {
607 super.interfaceClass(on, value);
608 return this;
609 }
610
611 @Override /* Overridden from Builder */
612 public Builder interfaces(java.lang.Class<?>...value) {
613 super.interfaces(value);
614 return this;
615 }
616
617 /**
618 * Parser listener.
619 *
620 * <p>
621 * Class used to listen for errors and warnings that occur during parsing.
622 *
623 * <h5 class='section'>Example:</h5>
624 * <p class='bjava'>
625 * <jc>// Define our parser listener.</jc>
626 * <jc>// Simply captures all unknown bean property events.</jc>
627 * <jk>public class</jk> MyParserListener <jk>extends</jk> ParserListener {
628 *
629 * <jc>// A simple property to store our events.</jc>
630 * <jk>public</jk> List<String> <jf>events</jf> = <jk>new</jk> LinkedList<>();
631 *
632 * <ja>@Override</ja>
633 * <jk>public</jk> <T> <jk>void</jk> onUnknownBeanProperty(ParserSession <jv>session</jv>, String <jv>propertyName</jv>, Class<T> <jv>beanClass</jv>, T <jv>bean</jv>) {
634 * Position <jv>position</jv> = <jv>parser</jv>.getPosition();
635 * <jf>events</jf>.add(<jv>propertyName</jv> + <js>","</js> + <jv>position</jv>.getLine() + <js>","</js> + <jv>position</jv>.getColumn());
636 * }
637 * }
638 *
639 * <jc>// Create a parser using our listener.</jc>
640 * ReaderParser <jv>parser</jv> = JsonParser
641 * .<jsm>create</jsm>()
642 * .listener(MyParserListener.<jk>class</jk>)
643 * .build();
644 *
645 * <jc>// Create a session object.</jc>
646 * <jc>// Needed because listeners are created per-session.</jc>
647 * <jk>try</jk> (ReaderParserSession <jv>session</jv> = <jv>parser</jv>.createSession()) {
648 *
649 * <jc>// Parse some JSON object.</jc>
650 * MyBean <jv>myBean</jv> = <jv>session</jv>.parse(<js>"{...}"</js>, MyBean.<jk>class</jk>);
651 *
652 * <jc>// Get the listener.</jc>
653 * MyParserListener <jv>listener</jv> = <jv>session</jv>.getListener(MyParserListener.<jk>class</jk>);
654 *
655 * <jc>// Dump the results to the console.</jc>
656 * Json5.<jsf>DEFAULT</jsf>.println(<jv>listener</jv>.<jf>events</jf>);
657 * }
658 * </p>
659 *
660 * @param value The new value for this property.
661 * <br>Can be <jk>null</jk>.
662 * @return This object.
663 */
664 public Builder listener(Class<? extends ParserListener> value) {
665 listener = value;
666 return this;
667 }
668
669 @Override /* Overridden from Builder */
670 public Builder locale(Locale value) {
671 super.locale(value);
672 return this;
673 }
674
675 @Override /* Overridden from Builder */
676 public Builder mediaType(MediaType value) {
677 super.mediaType(value);
678 return this;
679 }
680
681 @Override /* Overridden from Builder */
682 public Builder notBeanClasses(java.lang.Class<?>...values) {
683 super.notBeanClasses(values);
684 return this;
685 }
686
687 @Override /* Overridden from Builder */
688 public Builder notBeanPackages(String...values) {
689 super.notBeanPackages(values);
690 return this;
691 }
692
693 @Override /* Overridden from Builder */
694 public Builder propertyNamer(Class<?> on, Class<? extends org.apache.juneau.PropertyNamer> value) {
695 super.propertyNamer(on, value);
696 return this;
697 }
698
699 @Override /* Overridden from Builder */
700 public Builder propertyNamer(Class<? extends org.apache.juneau.PropertyNamer> value) {
701 super.propertyNamer(value);
702 return this;
703 }
704
705 @Override /* Overridden from Builder */
706 public Builder sortProperties() {
707 super.sortProperties();
708 return this;
709 }
710
711 @Override /* Overridden from Builder */
712 public Builder sortProperties(java.lang.Class<?>...on) {
713 super.sortProperties(on);
714 return this;
715 }
716
717 @Override /* Overridden from Builder */
718 public Builder stopClass(Class<?> on, Class<?> value) {
719 super.stopClass(on, value);
720 return this;
721 }
722
723 /**
724 * Strict mode.
725 *
726 * <p>
727 * When enabled, strict mode for the parser is enabled.
728 *
729 * <p>
730 * Strict mode can mean different things for different parsers.
731 *
732 * <table class='styled'>
733 * <tr><th>Parser class</th><th>Strict behavior</th></tr>
734 * <tr>
735 * <td>All reader-based parsers</td>
736 * <td>
737 * When enabled, throws {@link ParseException ParseExceptions} on malformed charset input.
738 * Otherwise, malformed input is ignored.
739 * </td>
740 * </tr>
741 * <tr>
742 * <td>{@link JsonParser}</td>
743 * <td>
744 * When enabled, throws exceptions on the following invalid JSON syntax:
745 * <ul>
746 * <li>Unquoted attributes.
747 * <li>Missing attribute values.
748 * <li>Concatenated strings.
749 * <li>Javascript comments.
750 * <li>Numbers and booleans when Strings are expected.
751 * <li>Numbers valid in Java but not JSON (e.g. octal notation, etc...)
752 * </ul>
753 * </td>
754 * </tr>
755 * </table>
756 *
757 * <h5 class='section'>Example:</h5>
758 * <p class='bjava'>
759 * <jc>// Create a parser using strict mode.</jc>
760 * ReaderParser <jv>parser</jv> = JsonParser
761 * .<jsm>create</jsm>()
762 * .strict()
763 * .build();
764 *
765 * <jc>// Use it.</jc>
766 * <jk>try</jk> {
767 * String <jv>json</jv> = <js>"{unquotedAttr:'value'}"</js>;
768 * <jv>parser</jv>.parse(<jv>json</jv>, MyBean.<jk>class</jk>);
769 * } <jk>catch</jk> (ParseException <jv>e</jv>) {
770 * <jsm>assertTrue</jsm>(<jv>e</jv>.getMessage().contains(<js>"Unquoted attribute detected."</js>);
771 * }
772 * </p>
773 *
774 * @return This object.
775 */
776 public Builder strict() {
777 return strict(true);
778 }
779
780 /**
781 * Same as {@link #strict()} but allows you to explicitly specify the value.
782 *
783 * @param value The value for this setting.
784 * @return This object.
785 */
786 public Builder strict(boolean value) {
787 strict = value;
788 return this;
789 }
790
791 @Override /* Overridden from Builder */
792 public <T,S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction) {
793 super.swap(normalClass, swappedClass, swapFunction);
794 return this;
795 }
796
797 @Override /* Overridden from Builder */
798 public <T,S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction, ThrowingFunction<S,T> unswapFunction) {
799 super.swap(normalClass, swappedClass, swapFunction, unswapFunction);
800 return this;
801 }
802
803 @Override /* Overridden from Builder */
804 public Builder swaps(Class<?>...values) {
805 super.swaps(values);
806 return this;
807 }
808
809 @Override /* Overridden from Builder */
810 public Builder swaps(Object...values) {
811 super.swaps(values);
812 return this;
813 }
814
815 @Override /* Overridden from Builder */
816 public Builder timeZone(TimeZone value) {
817 super.timeZone(value);
818 return this;
819 }
820
821 /**
822 * Trim parsed strings.
823 *
824 * <p>
825 * When enabled, string values will be trimmed of whitespace using {@link String#trim()} before being added to
826 * the POJO.
827 *
828 * <h5 class='section'>Example:</h5>
829 * <p class='bjava'>
830 * <jc>// Create a parser with trim-strings enabled.</jc>
831 * ReaderParser <jv>parser</jv> = JsonParser
832 * .<jsm>create</jsm>()
833 * .trimStrings()
834 * .build();
835 *
836 * <jc>// Use it.</jc>
837 * String <jv>json</jv> = <js>"{' foo ':' bar '}"</js>;
838 * Map<String,String> <jv>myMap</jv> = <jv>parser</jv>.parse(<jv>json</jv>, HashMap.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>);
839 *
840 * <jc>// Make sure strings are parsed.</jc>
841 * <jsm>assertEquals</jsm>(<js>"bar"</js>, <jv>myMap</jv>.get(<js>"foo"</js>));
842 * </p>
843 *
844 * @return This object.
845 */
846 public Builder trimStrings() {
847 return trimStrings(true);
848 }
849
850 /**
851 * Same as {@link #trimStrings()} but allows you to explicitly specify the value.
852 *
853 * @param value The value for this setting.
854 * @return This object.
855 */
856 public Builder trimStrings(boolean value) {
857 trimStrings = value;
858 return this;
859 }
860
861 @Override /* Overridden from Builder */
862 public Builder type(Class<? extends org.apache.juneau.Context> value) {
863 super.type(value);
864 return this;
865 }
866
867 @Override /* Overridden from Builder */
868 public Builder typeName(Class<?> on, String value) {
869 super.typeName(on, value);
870 return this;
871 }
872
873 @Override /* Overridden from Builder */
874 public Builder typePropertyName(Class<?> on, String value) {
875 super.typePropertyName(on, value);
876 return this;
877 }
878
879 @Override /* Overridden from Builder */
880 public Builder typePropertyName(String value) {
881 super.typePropertyName(value);
882 return this;
883 }
884
885 /**
886 * Unbuffered.
887 *
888 * <p>
889 * When enabled, don't use internal buffering during parsing.
890 *
891 * <p>
892 * This is useful in cases when you want to parse the same input stream or reader multiple times
893 * because it may contain multiple independent POJOs to parse.
894 * <br>Buffering would cause the parser to read past the current POJO in the stream.
895 *
896 * <h5 class='section'>Example:</h5>
897 * <p class='bjava'>
898 * <jc>// Create a parser using strict mode.</jc>
899 * ReaderParser <jv>parser</jv> = JsonParser.
900 * .<jsm>create</jsm>()
901 * .unbuffered(<jk>true</jk>)
902 * .build();
903 *
904 * <jc>// If you're calling parse on the same input multiple times, use a session instead of the parser directly.</jc>
905 * <jc>// It's more efficient because we don't need to recalc the session settings again. </jc>
906 * ReaderParserSession <jv>session</jv> = <jv>parser</jv>.createSession();
907 *
908 * <jc>// Read input with multiple POJOs</jc>
909 * Reader <jv>json</jv> = <jk>new</jk> StringReader(<js>"{foo:'bar'}{foo:'baz'}"</js>);
910 * MyBean <jv>myBean1</jv> = <jv>session</jv>.parse(<jv>json</jv>, MyBean.<jk>class</jk>);
911 * MyBean <jv>myBean2</jv> = <jv>session</jv>.parse(<jv>json</jv>, MyBean.<jk>class</jk>);
912 * </p>
913 *
914 * <h5 class='section'>Notes:</h5><ul>
915 * <li class='note'>
916 * This only allows for multi-input streams for the following parsers:
917 * <ul>
918 * <li class='jc'>{@link JsonParser}
919 * <li class='jc'>{@link UonParser}
920 * </ul>
921 * It has no effect on the following parsers:
922 * <ul>
923 * <li class='jc'>{@link MsgPackParser} - It already doesn't use buffering.
924 * <li class='jc'>{@link XmlParser}, {@link HtmlParser} - These use StAX which doesn't allow for more than one root element anyway.
925 * <li>RDF parsers - These read everything into an internal model before any parsing begins.
926 * </ul>
927 * </ul>
928 *
929 * @return This object.
930 */
931 public Builder unbuffered() {
932 return unbuffered(true);
933 }
934
935 /**
936 * Same as {@link #unbuffered()} but allows you to explicitly specify the value.
937 *
938 * @param value The value for this setting.
939 * @return This object.
940 */
941 public Builder unbuffered(boolean value) {
942 unbuffered = value;
943 return this;
944 }
945
946 @Override /* Overridden from Builder */
947 public Builder useEnumNames() {
948 super.useEnumNames();
949 return this;
950 }
951
952 @Override /* Overridden from Builder */
953 public Builder useJavaBeanIntrospector() {
954 super.useJavaBeanIntrospector();
955 return this;
956 }
957 }
958
959 /**
960 * Represents no Parser.
961 */
962 public static abstract class Null extends Parser {
963 private Null(Builder builder) {
964 super(builder);
965 }
966 }
967
968 /**
969 * Creates a new builder for this object.
970 *
971 * @return A new builder.
972 */
973 public static Builder create() {
974 return new Builder();
975 }
976
977 /**
978 * Instantiates a builder of the specified parser class.
979 *
980 * <p>
981 * Looks for a public static method called <c>create</c> that returns an object that can be passed into a public
982 * or protected constructor of the class.
983 *
984 * @param c The builder to create.
985 * @return A new builder.
986 */
987 public static Builder createParserBuilder(Class<? extends Parser> c) {
988 return (Builder)Context.createBuilder(c);
989 }
990
991 protected final boolean autoCloseStreams;
992 protected final boolean strict;
993 protected final boolean trimStrings;
994 protected final boolean unbuffered;
995 protected final int debugOutputLines;
996 protected final Class<? extends ParserListener> listener;
997 protected final String consumes;
998 private final List<MediaType> consumesArray;
999
1000 /**
1001 * Constructor.
1002 *
1003 * @param builder The builder this object.
1004 */
1005 protected Parser(Builder builder) {
1006 super(builder);
1007
1008 autoCloseStreams = builder.autoCloseStreams;
1009 consumes = builder.consumes;
1010 debugOutputLines = builder.debugOutputLines;
1011 listener = builder.listener;
1012 strict = builder.strict;
1013 trimStrings = builder.trimStrings;
1014 unbuffered = builder.unbuffered;
1015
1016 String[] _consumes = splita(nn(consumes) ? consumes : "");
1017 List<MediaType> _consumesList = new ArrayList<>();
1018 for (var consume : _consumes) {
1019 _consumesList.add(MediaType.of(consume));
1020 }
1021 this.consumesArray = u(_consumesList);
1022 }
1023
1024 /**
1025 * Returns <jk>true</jk> if this parser can handle the specified content type.
1026 *
1027 * @param contentType The content type to test.
1028 * @return <jk>true</jk> if this parser can handle the specified content type.
1029 */
1030 public boolean canHandle(String contentType) {
1031 if (nn(contentType))
1032 for (var mt : getMediaTypes())
1033 if (contentType.equals(mt.toString()))
1034 return true;
1035 return false;
1036 }
1037
1038 @Override /* Overridden from Context */
1039 public Builder copy() {
1040 return new Builder(this);
1041 }
1042
1043 @Override /* Overridden from Context */
1044 public ParserSession.Builder createSession() {
1045 return ParserSession.create(this);
1046 }
1047
1048 /**
1049 * Workhorse method.
1050 *
1051 * <p>
1052 * Subclasses are expected to either implement this method or {@link ParserSession#doParse(ParserPipe, ClassMeta)}.
1053 *
1054 * @param session The current session.
1055 * @param pipe Where to get the input from.
1056 * @param type
1057 * The class type of the object to create.
1058 * If <jk>null</jk> or <code>Object.<jk>class</jk></code>, object type is based on what's being parsed.
1059 * For example, when parsing JSON text, it may return a <c>String</c>, <c>Number</c>,
1060 * <c>JsonMap</c>, etc...
1061 * @param <T> The class type of the object to create.
1062 * @return The parsed object.
1063 * @throws IOException Thrown by underlying stream.
1064 * @throws ParseException Malformed input encountered.
1065 * @throws ExecutableException Exception occurred on invoked constructor/method/field.
1066 */
1067 public <T> T doParse(ParserSession session, ParserPipe pipe, ClassMeta<T> type) throws IOException, ParseException {
1068 throw unsupportedOp();
1069 }
1070
1071 /**
1072 * Returns the media types handled based on the values passed to the <c>consumes</c> constructor parameter.
1073 *
1074 * @return The list of media types. Never <jk>null</jk>.
1075 */
1076 public final List<MediaType> getMediaTypes() { return consumesArray; }
1077
1078 /**
1079 * Returns the first media type handled based on the values passed to the <c>consumes</c> constructor parameter.
1080 *
1081 * @return The media type.
1082 */
1083 public final MediaType getPrimaryMediaType() { return consumesArray.isEmpty() ? null : consumesArray.get(0); }
1084
1085 @Override /* Overridden from Context */
1086 public ParserSession getSession() { return createSession().build(); }
1087
1088 /**
1089 * Returns <jk>true</jk> if this parser subclasses from {@link ReaderParser}.
1090 *
1091 * @return <jk>true</jk> if this parser subclasses from {@link ReaderParser}.
1092 */
1093 public boolean isReaderParser() { return true; }
1094
1095 /**
1096 * Same as {@link #parse(Object, Type, Type...)} except optimized for a non-parameterized class.
1097 *
1098 * <p>
1099 * This is the preferred parse method for simple types since you don't need to cast the results.
1100 *
1101 * <h5 class='section'>Examples:</h5>
1102 * <p class='bjava'>
1103 * ReaderParser <jv>parser</jv> = JsonParser.<jsf>DEFAULT</jsf>;
1104 *
1105 * <jc>// Parse into a string.</jc>
1106 * String <jv>string</jv> = <jv>parser</jv>.parse(<jv>json</jv>, String.<jk>class</jk>);
1107 *
1108 * <jc>// Parse into a bean.</jc>
1109 * MyBean <jv>bean</jv> = <jv>parser</jv>.parse(<jv>json</jv>, MyBean.<jk>class</jk>);
1110 *
1111 * <jc>// Parse into a bean array.</jc>
1112 * MyBean[] <jv>beanArray</jv> = <jv>parser</jv>.parse(<jv>json</jv>, MyBean[].<jk>class</jk>);
1113 *
1114 * <jc>// Parse into a linked-list of objects.</jc>
1115 * List <jv>list</jv> = <jv>parser</jv>.parse(<jv>json</jv>, LinkedList.<jk>class</jk>);
1116 *
1117 * <jc>// Parse into a map of object keys/values.</jc>
1118 * Map <jv>map</jv> = <jv>parser</jv>.parse(<jv>json</jv>, TreeMap.<jk>class</jk>);
1119 * </p>
1120 *
1121 * @param <T> The class type of the object being created.
1122 * @param input
1123 * The input.
1124 * See {@link #parse(Object, Type, Type...)} for details.
1125 * @param type The object type to create.
1126 * @return The parsed object.
1127 * @throws ParseException Malformed input encountered.
1128 * @throws IOException Thrown by the underlying stream.
1129 */
1130 public final <T> T parse(Object input, Class<T> type) throws ParseException, IOException {
1131 return getSession().parse(input, type);
1132 }
1133
1134 /**
1135 * Same as {@link #parse(Object, Type, Type...)} except the type has already been converted into a {@link ClassMeta}
1136 * object.
1137 *
1138 * <p>
1139 * This is mostly an internal method used by the framework.
1140 *
1141 * @param <T> The class type of the object being created.
1142 * @param input
1143 * The input.
1144 * See {@link #parse(Object, Type, Type...)} for details.
1145 * @param type The object type to create.
1146 * @return The parsed object.
1147 * @throws ParseException Malformed input encountered.
1148 * @throws IOException Thrown by the underlying stream.
1149 */
1150 public final <T> T parse(Object input, ClassMeta<T> type) throws ParseException, IOException {
1151 return getSession().parse(input, type);
1152 }
1153
1154 /**
1155 * Parses input into the specified object type.
1156 *
1157 * <p>
1158 * The type can be a simple type (e.g. beans, strings, numbers) or parameterized type (collections/maps).
1159 *
1160 * <h5 class='section'>Examples:</h5>
1161 * <p class='bjava'>
1162 * ReaderParser <jv>parser</jv> = JsonParser.<jsf>DEFAULT</jsf>;
1163 *
1164 * <jc>// Parse into a linked-list of strings.</jc>
1165 * List <jv>list1</jv> = <jv>parser</jv>.parse(<jv>json</jv>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);
1166 *
1167 * <jc>// Parse into a linked-list of beans.</jc>
1168 * List <jv>list2</jv> = <jv>parser</jv>.parse(<jv>json</jv>, LinkedList.<jk>class</jk>, MyBean.<jk>class</jk>);
1169 *
1170 * <jc>// Parse into a linked-list of linked-lists of strings.</jc>
1171 * List <jv>list3</jv> = <jv>parser</jv>.parse(<jv>json</jv>, LinkedList.<jk>class</jk>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);
1172 *
1173 * <jc>// Parse into a map of string keys/values.</jc>
1174 * Map <jv>map1</jv> = <jv>parser</jv>.parse(<jv>json</jv>, TreeMap.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>);
1175 *
1176 * <jc>// Parse into a map containing string keys and values of lists containing beans.</jc>
1177 * Map <jv>map2</jv> = <jv>parser</jv>.parse(<jv>json</jv>, TreeMap.<jk>class</jk>, String.<jk>class</jk>, List.<jk>class</jk>, MyBean.<jk>class</jk>);
1178 * </p>
1179 *
1180 * <p>
1181 * <c>Collection</c> classes are assumed to be followed by zero or one objects indicating the element type.
1182 *
1183 * <p>
1184 * <c>Map</c> classes are assumed to be followed by zero or two meta objects indicating the key and value types.
1185 *
1186 * <p>
1187 * The array can be arbitrarily long to indicate arbitrarily complex data structures.
1188 *
1189 * <h5 class='section'>Notes:</h5><ul>
1190 * <li class='note'>
1191 * Use the {@link #parse(Object, Class)} method instead if you don't need a parameterized map/collection.
1192 * </ul>
1193 *
1194 * @param <T> The class type of the object to create.
1195 * @param input
1196 * The input.
1197 * <br>Character-based parsers can handle the following input class types:
1198 * <ul>
1199 * <li><jk>null</jk>
1200 * <li>{@link Reader}
1201 * <li>{@link CharSequence}
1202 * <li>{@link InputStream} containing UTF-8 encoded text (or charset defined by
1203 * {@link ReaderParser.Builder#streamCharset(Charset)} property value).
1204 * <li><code><jk>byte</jk>[]</code> containing UTF-8 encoded text (or charset defined by
1205 * {@link ReaderParser.Builder#streamCharset(Charset)} property value).
1206 * <li>{@link File} containing system encoded text (or charset defined by
1207 * {@link ReaderParser.Builder#fileCharset(Charset)} property value).
1208 * </ul>
1209 * <br>Stream-based parsers can handle the following input class types:
1210 * <ul>
1211 * <li><jk>null</jk>
1212 * <li>{@link InputStream}
1213 * <li><code><jk>byte</jk>[]</code>
1214 * <li>{@link File}
1215 * <li>{@link CharSequence} containing encoded bytes according to the {@link InputStreamParser.Builder#binaryFormat(BinaryFormat)} setting.
1216 * </ul>
1217 * @param type
1218 * The object type to create.
1219 * <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
1220 * @param args
1221 * The type arguments of the class if it's a collection or map.
1222 * <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
1223 * <br>Ignored if the main type is not a map or collection.
1224 * @return The parsed object.
1225 * @throws ParseException Malformed input encountered.
1226 * @throws IOException Thrown by underlying stream.
1227 * @see BeanSession#getClassMeta(Type,Type...) for argument syntax for maps and collections.
1228 */
1229 public final <T> T parse(Object input, Type type, Type...args) throws ParseException, IOException {
1230 return getSession().parse(input, type, args);
1231 }
1232
1233 /**
1234 * Same as {@link #parse(Object, Class)} but since it's a {@link String} input doesn't throw an {@link IOException}.
1235 *
1236 * @param <T> The class type of the object being created.
1237 * @param input
1238 * The input.
1239 * See {@link #parse(Object, Type, Type...)} for details.
1240 * @param type The object type to create.
1241 * @return The parsed object.
1242 * @throws ParseException Malformed input encountered.
1243 */
1244 public final <T> T parse(String input, Class<T> type) throws ParseException {
1245 return getSession().parse(input, type);
1246 }
1247
1248 /**
1249 * Same as {@link #parse(Object, ClassMeta)} but since it's a {@link String} input doesn't throw an {@link IOException}.
1250 *
1251 * @param <T> The class type of the object being created.
1252 * @param input
1253 * The input.
1254 * See {@link #parse(Object, Type, Type...)} for details.
1255 * @param type The object type to create.
1256 * @return The parsed object.
1257 * @throws ParseException Malformed input encountered.
1258 */
1259 public final <T> T parse(String input, ClassMeta<T> type) throws ParseException {
1260 return getSession().parse(input, type);
1261 }
1262
1263 /**
1264 * Same as {@link #parse(Object, Type, Type...)} but since it's a {@link String} input doesn't throw an {@link IOException}.
1265 *
1266 * @param <T> The class type of the object being created.
1267 * @param input
1268 * The input.
1269 * See {@link #parse(Object, Type, Type...)} for details.
1270 * @param type
1271 * The object type to create.
1272 * <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
1273 * @param args
1274 * The type arguments of the class if it's a collection or map.
1275 * <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
1276 * <br>Ignored if the main type is not a map or collection.
1277 * @return The parsed object.
1278 * @throws ParseException Malformed input encountered.
1279 */
1280 public final <T> T parse(String input, Type type, Type...args) throws ParseException {
1281 return getSession().parse(input, type, args);
1282 }
1283
1284 /**
1285 * Parses the specified array input with each entry in the object defined by the {@code argTypes}
1286 * argument.
1287 *
1288 * <p>
1289 * Used for converting arrays (e.g. <js>"[arg1,arg2,...]"</js>) into an {@code Object[]} that can be passed
1290 * to the {@code Method.invoke(target, args)} method.
1291 *
1292 * <p>
1293 * Used in the following locations:
1294 * <ul class='spaced-list'>
1295 * <li>
1296 * Used to parse argument strings in the {@link ObjectIntrospector#invokeMethod(Method, Reader)} method.
1297 * </ul>
1298 *
1299 * @param input The input. Subclasses can support different input types.
1300 * @param argTypes Specifies the type of objects to create for each entry in the array.
1301 * @return An array of parsed objects.
1302 * @throws ParseException Malformed input encountered.
1303 */
1304 public final Object[] parseArgs(Object input, Type[] argTypes) throws ParseException {
1305 if (argTypes == null || argTypes.length == 0)
1306 return new Object[0];
1307 return getSession().parseArgs(input, argTypes);
1308 }
1309
1310 /**
1311 * Parses the contents of the specified reader and loads the results into the specified collection.
1312 *
1313 * <p>
1314 * Used in the following locations:
1315 * <ul class='spaced-list'>
1316 * <li>
1317 * The various character-based constructors in {@link JsonList} (e.g.
1318 * {@link JsonList#JsonList(CharSequence,Parser)}.
1319 * </ul>
1320 *
1321 * @param <E> The element class type.
1322 * @param input The input. See {@link #parse(Object, ClassMeta)} for supported input types.
1323 * @param c The collection being loaded.
1324 * @param elementType The class type of the elements, or <jk>null</jk> to default to whatever is being parsed.
1325 * @return The same collection that was passed in to allow this method to be chained.
1326 * @throws ParseException Malformed input encountered.
1327 * @throws UnsupportedOperationException If not implemented.
1328 */
1329 public final <E> Collection<E> parseIntoCollection(Object input, Collection<E> c, Type elementType) throws ParseException {
1330 return getSession().parseIntoCollection(input, c, elementType);
1331 }
1332
1333 /**
1334 * Parses the contents of the specified reader and loads the results into the specified map.
1335 *
1336 * <p>
1337 * Reader must contain something that serializes to a map (such as text containing a JSON object).
1338 *
1339 * <p>
1340 * Used in the following locations:
1341 * <ul class='spaced-list'>
1342 * <li>
1343 * The various character-based constructors in {@link JsonMap} (e.g.
1344 * {@link JsonMap#JsonMap(CharSequence,Parser)}).
1345 * </ul>
1346 *
1347 * @param <K> The key class type.
1348 * @param <V> The value class type.
1349 * @param input The input. See {@link #parse(Object, ClassMeta)} for supported input types.
1350 * @param m The map being loaded.
1351 * @param keyType The class type of the keys, or <jk>null</jk> to default to <code>String.<jk>class</jk></code>.
1352 * @param valueType The class type of the values, or <jk>null</jk> to default to whatever is being parsed.
1353 * @return The same map that was passed in to allow this method to be chained.
1354 * @throws ParseException Malformed input encountered.
1355 * @throws UnsupportedOperationException If not implemented.
1356 */
1357 public final <K,V> Map<K,V> parseIntoMap(Object input, Map<K,V> m, Type keyType, Type valueType) throws ParseException {
1358 return getSession().parseIntoMap(input, m, keyType, valueType);
1359 }
1360
1361 /**
1362 * Debug output lines.
1363 *
1364 * @see Parser.Builder#debugOutputLines(int)
1365 * @return
1366 * The number of lines of input before and after the error location to be printed as part of the exception message.
1367 */
1368 protected final int getDebugOutputLines() { return debugOutputLines; }
1369
1370 /**
1371 * Parser listener.
1372 *
1373 * @see Parser.Builder#listener(Class)
1374 * @return
1375 * Class used to listen for errors and warnings that occur during parsing.
1376 */
1377 protected final Class<? extends ParserListener> getListener() { return listener; }
1378
1379 /**
1380 * Auto-close streams.
1381 *
1382 * @see Parser.Builder#autoCloseStreams()
1383 * @return
1384 * <jk>true</jk> if <l>InputStreams</l> and <l>Readers</l> passed into parsers will be closed
1385 * after parsing is complete.
1386 */
1387 protected final boolean isAutoCloseStreams() { return autoCloseStreams; }
1388
1389 /**
1390 * Strict mode.
1391 *
1392 * @see Parser.Builder#strict()
1393 * @return
1394 * <jk>true</jk> if strict mode for the parser is enabled.
1395 */
1396 protected final boolean isStrict() { return strict; }
1397
1398 /**
1399 * Trim parsed strings.
1400 *
1401 * @see Parser.Builder#trimStrings()
1402 * @return
1403 * <jk>true</jk> if string values will be trimmed of whitespace using {@link String#trim()} before being added to
1404 * the POJO.
1405 */
1406 protected final boolean isTrimStrings() { return trimStrings; }
1407
1408 /**
1409 * Unbuffered.
1410 *
1411 * @see Parser.Builder#unbuffered()
1412 * @return
1413 * <jk>true</jk> if parsers don't use internal buffering during parsing.
1414 */
1415 protected final boolean isUnbuffered() { return unbuffered; }
1416
1417 @Override /* Overridden from BeanContextable */
1418 protected FluentMap<String,Object> properties() {
1419 return super.properties()
1420 .a("autoCloseStreams", autoCloseStreams)
1421 .a("debugOutputLines", debugOutputLines)
1422 .a("listener", listener)
1423 .a("strict", strict)
1424 .a("trimStrings", trimStrings)
1425 .a("unbuffered", unbuffered);
1426 }
1427 }