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.parser; 018 019import static org.apache.juneau.commons.utils.CollectionUtils.*; 020import static org.apache.juneau.commons.utils.StringUtils.*; 021import static org.apache.juneau.commons.utils.ThrowableUtils.*; 022import static org.apache.juneau.commons.utils.Utils.*; 023 024import java.io.*; 025import java.lang.annotation.*; 026import java.lang.reflect.*; 027import java.nio.charset.*; 028import java.util.*; 029 030import org.apache.juneau.*; 031import org.apache.juneau.collections.*; 032import org.apache.juneau.commons.collections.*; 033import org.apache.juneau.commons.function.*; 034import org.apache.juneau.commons.reflect.*; 035import org.apache.juneau.html.*; 036import org.apache.juneau.json.*; 037import org.apache.juneau.msgpack.*; 038import org.apache.juneau.objecttools.*; 039import org.apache.juneau.swap.*; 040import org.apache.juneau.swaps.*; 041import org.apache.juneau.uon.*; 042import org.apache.juneau.xml.*; 043 044/** 045 * Parent class for all Juneau parsers. 046 * 047 * <h5 class='topic'>Valid data conversions</h5> 048 * <p> 049 * 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>. 050 * 051 * <p> 052 * Some examples of conversions are shown below... 053 * </p> 054 * <table class='styled'> 055 * <tr> 056 * <th>Data type</th> 057 * <th>Class type</th> 058 * <th>JSON example</th> 059 * <th>XML example</th> 060 * <th>Class examples</th> 061 * </tr> 062 * <tr> 063 * <td>object</td> 064 * <td>Maps, Java beans</td> 065 * <td class='code'>{name:<js>'John Smith'</js>,age:21}</td> 066 * <td class='code'><xt><object> 067 * <name</xt> <xa>type</xa>=<xs>'string'</xs><xt>></xt>John Smith<xt></name> 068 * <age</xt> <xa>type</xa>=<xs>'number'</xs><xt>></xt>21<xt></age> 069 * </object></xt></td> 070 * <td class='code'>HashMap, TreeMap<String,Integer></td> 071 * </tr> 072 * <tr> 073 * <td>array</td> 074 * <td>Collections, Java arrays</td> 075 * <td class='code'>[1,2,3]</td> 076 * <td class='code'><xt><array> 077 * <number></xt>1<xt></number> 078 * <number></xt>2<xt></number> 079 * <number></xt>3<xt></number> 080 * </array></xt></td> 081 * <td class='code'>List<Integer>, <jk>int</jk>[], Float[], Set<Person></td> 082 * </tr> 083 * <tr> 084 * <td>number</td> 085 * <td>Numbers</td> 086 * <td class='code'>123</td> 087 * <td class='code'><xt><number></xt>123<xt></number></xt></td> 088 * <td class='code'>Integer, Long, Float, <jk>int</jk></td> 089 * </tr> 090 * <tr> 091 * <td>boolean</td> 092 * <td>Booleans</td> 093 * <td class='code'><jk>true</jk></td> 094 * <td class='code'><xt><boolean></xt>true<xt></boolean></xt></td> 095 * <td class='code'>Boolean</td> 096 * </tr> 097 * <tr> 098 * <td>string</td> 099 * <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 */ 141public 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}