1 package com.fasterxml.jackson.databind.util; 2 3 import java.io.*; 4 import java.math.BigDecimal; 5 import java.math.BigInteger; 6 import java.util.TreeMap; 7 8 import com.fasterxml.jackson.core.*; 9 import com.fasterxml.jackson.core.base.ParserMinimalBase; 10 import com.fasterxml.jackson.core.json.JsonWriteContext; 11 import com.fasterxml.jackson.core.util.ByteArrayBuilder; 12 import com.fasterxml.jackson.core.util.JacksonFeatureSet; 13 import com.fasterxml.jackson.databind.*; 14 15 /** 16 * Utility class used for efficient storage of {@link JsonToken} 17 * sequences, needed for temporary buffering. 18 * Space efficient for different sequence lengths (especially so for smaller 19 * ones; but not significantly less efficient for larger), highly efficient 20 * for linear iteration and appending. Implemented as segmented/chunked 21 * linked list of tokens; only modifications are via appends. 22 *<p> 23 * Note that before version 2.0, this class was located in the "core" 24 * bundle, not data-binding; but since it was only used by data binding, 25 * was moved here to reduce size of core package 26 */ 27 public class TokenBuffer 28 /* Won't use JsonGeneratorBase, to minimize overhead for validity 29 * checking 30 */ 31 extends JsonGenerator 32 { 33 protected final static int DEFAULT_GENERATOR_FEATURES = JsonGenerator.Feature.collectDefaults(); 34 35 /* 36 /********************************************************** 37 /* Configuration 38 /********************************************************** 39 */ 40 41 /** 42 * Object codec to use for stream-based object 43 * conversion through parser/generator interfaces. If null, 44 * such methods cannot be used. 45 */ 46 protected ObjectCodec _objectCodec; 47 48 /** 49 * Parse context from "parent" parser (one from which content to buffer is read, 50 * if specified). Used, if available, when reading content, to present full 51 * context as if content was read from the original parser: this is useful 52 * in error reporting and sometimes processing as well. 53 */ 54 protected JsonStreamContext _parentContext; 55 56 /** 57 * Bit flag composed of bits that indicate which 58 * {@link com.fasterxml.jackson.core.JsonGenerator.Feature}s 59 * are enabled. 60 *<p> 61 * NOTE: most features have no effect on this class 62 */ 63 protected int _generatorFeatures; 64 65 protected boolean _closed; 66 67 /** 68 * @since 2.3 69 */ 70 protected boolean _hasNativeTypeIds; 71 72 /** 73 * @since 2.3 74 */ 75 protected boolean _hasNativeObjectIds; 76 77 /** 78 * @since 2.3 79 */ 80 protected boolean _mayHaveNativeIds; 81 82 /** 83 * Flag set during construction, if use of {@link BigDecimal} is to be forced 84 * on all floating-point values. 85 * 86 * @since 2.7 87 */ 88 protected boolean _forceBigDecimal; 89 90 /* 91 /********************************************************** 92 /* Token buffering state 93 /********************************************************** 94 */ 95 96 /** 97 * First segment, for contents this buffer has 98 */ 99 protected Segment _first; 100 101 /** 102 * Last segment of this buffer, one that is used 103 * for appending more tokens 104 */ 105 protected Segment _last; 106 107 /** 108 * Offset within last segment, 109 */ 110 protected int _appendAt; 111 112 /** 113 * If native type ids supported, this is the id for following 114 * value (or first token of one) to be written. 115 */ 116 protected Object _typeId; 117 118 /** 119 * If native object ids supported, this is the id for following 120 * value (or first token of one) to be written. 121 */ 122 protected Object _objectId; 123 124 /** 125 * Do we currently have a native type or object id buffered? 126 */ 127 protected boolean _hasNativeId = false; 128 129 /* 130 /********************************************************** 131 /* Output state 132 /********************************************************** 133 */ 134 135 protected JsonWriteContext _writeContext; 136 137 /* 138 /********************************************************** 139 /* Life-cycle 140 /********************************************************** 141 */ 142 143 /** 144 * @param codec Object codec to use for stream-based object 145 * conversion through parser/generator interfaces. If null, 146 * such methods cannot be used. 147 * @param hasNativeIds Whether resulting {@link JsonParser} (if created) 148 * is considered to support native type and object ids 149 */ TokenBuffer(ObjectCodec codec, boolean hasNativeIds)150 public TokenBuffer(ObjectCodec codec, boolean hasNativeIds) 151 { 152 _objectCodec = codec; 153 _generatorFeatures = DEFAULT_GENERATOR_FEATURES; 154 _writeContext = JsonWriteContext.createRootContext(null); 155 // at first we have just one segment 156 _first = _last = new Segment(); 157 _appendAt = 0; 158 _hasNativeTypeIds = hasNativeIds; 159 _hasNativeObjectIds = hasNativeIds; 160 161 _mayHaveNativeIds = _hasNativeTypeIds | _hasNativeObjectIds; 162 } 163 164 /** 165 * @since 2.3 166 */ TokenBuffer(JsonParser p)167 public TokenBuffer(JsonParser p) { 168 this(p, null); 169 } 170 171 /** 172 * @since 2.7 173 */ TokenBuffer(JsonParser p, DeserializationContext ctxt)174 public TokenBuffer(JsonParser p, DeserializationContext ctxt) 175 { 176 _objectCodec = p.getCodec(); 177 _parentContext = p.getParsingContext(); 178 _generatorFeatures = DEFAULT_GENERATOR_FEATURES; 179 _writeContext = JsonWriteContext.createRootContext(null); 180 // at first we have just one segment 181 _first = _last = new Segment(); 182 _appendAt = 0; 183 _hasNativeTypeIds = p.canReadTypeId(); 184 _hasNativeObjectIds = p.canReadObjectId(); 185 _mayHaveNativeIds = _hasNativeTypeIds | _hasNativeObjectIds; 186 _forceBigDecimal = (ctxt == null) ? false 187 : ctxt.isEnabled(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS); 188 } 189 190 /** 191 * Convenience method, equivalent to: 192 *<pre> 193 * TokenBuffer b = new TokenBuffer(p); 194 * b.copyCurrentStructure(p); 195 * return b; 196 *</pre> 197 * 198 * @since 2.9 199 */ asCopyOfValue(JsonParser p)200 public static TokenBuffer asCopyOfValue(JsonParser p) throws IOException { 201 TokenBuffer b = new TokenBuffer(p); 202 b.copyCurrentStructure(p); 203 return b; 204 } 205 206 /** 207 * Method that allows explicitly specifying parent parse context to associate 208 * with contents of this buffer. Usually context is assigned at construction, 209 * based on given parser; but it is not always available, and may not contain 210 * intended context. 211 * 212 * @since 2.9 213 */ overrideParentContext(JsonStreamContext ctxt)214 public TokenBuffer overrideParentContext(JsonStreamContext ctxt) { 215 _parentContext = ctxt; 216 return this; 217 } 218 219 /** 220 * @since 2.7 221 */ forceUseOfBigDecimal(boolean b)222 public TokenBuffer forceUseOfBigDecimal(boolean b) { 223 _forceBigDecimal = b; 224 return this; 225 } 226 227 @Override version()228 public Version version() { 229 return com.fasterxml.jackson.databind.cfg.PackageVersion.VERSION; 230 } 231 232 /** 233 * Method used to create a {@link JsonParser} that can read contents 234 * stored in this buffer. Will use default <code>_objectCodec</code> for 235 * object conversions. 236 *<p> 237 * Note: instances are not synchronized, that is, they are not thread-safe 238 * if there are concurrent appends to the underlying buffer. 239 * 240 * @return Parser that can be used for reading contents stored in this buffer 241 */ asParser()242 public JsonParser asParser() { 243 return asParser(_objectCodec); 244 } 245 246 /** 247 * Same as: 248 *<pre> 249 * JsonParser p = asParser(); 250 * p.nextToken(); 251 * return p; 252 *</pre> 253 * 254 * @since 2.9 255 */ asParserOnFirstToken()256 public JsonParser asParserOnFirstToken() throws IOException { 257 JsonParser p = asParser(_objectCodec); 258 p.nextToken(); 259 return p; 260 } 261 262 /** 263 * Method used to create a {@link JsonParser} that can read contents 264 * stored in this buffer. 265 *<p> 266 * Note: instances are not synchronized, that is, they are not thread-safe 267 * if there are concurrent appends to the underlying buffer. 268 * 269 * @param codec Object codec to use for stream-based object 270 * conversion through parser/generator interfaces. If null, 271 * such methods cannot be used. 272 * 273 * @return Parser that can be used for reading contents stored in this buffer 274 */ asParser(ObjectCodec codec)275 public JsonParser asParser(ObjectCodec codec) 276 { 277 return new Parser(_first, codec, _hasNativeTypeIds, _hasNativeObjectIds, _parentContext); 278 } 279 280 /** 281 * @param src Parser to use for accessing source information 282 * like location, configured codec 283 */ asParser(JsonParser src)284 public JsonParser asParser(JsonParser src) 285 { 286 Parser p = new Parser(_first, src.getCodec(), _hasNativeTypeIds, _hasNativeObjectIds, _parentContext); 287 p.setLocation(src.getTokenLocation()); 288 return p; 289 } 290 291 /* 292 /********************************************************** 293 /* Additional accessors 294 /********************************************************** 295 */ 296 firstToken()297 public JsonToken firstToken() { 298 // no need to null check; never create without `_first` 299 return _first.type(0); 300 } 301 302 /* 303 /********************************************************** 304 /* Other custom methods not needed for implementing interfaces 305 /********************************************************** 306 */ 307 308 /** 309 * Helper method that will append contents of given buffer into this 310 * buffer. 311 * Not particularly optimized; can be made faster if there is need. 312 * 313 * @return This buffer 314 */ 315 @SuppressWarnings("resource") append(TokenBuffer other)316 public TokenBuffer append(TokenBuffer other) throws IOException 317 { 318 // Important? If source has native ids, need to store 319 if (!_hasNativeTypeIds) { 320 _hasNativeTypeIds = other.canWriteTypeId(); 321 } 322 if (!_hasNativeObjectIds) { 323 _hasNativeObjectIds = other.canWriteObjectId(); 324 } 325 _mayHaveNativeIds = _hasNativeTypeIds | _hasNativeObjectIds; 326 327 JsonParser p = other.asParser(); 328 while (p.nextToken() != null) { 329 copyCurrentStructure(p); 330 } 331 return this; 332 } 333 334 /** 335 * Helper method that will write all contents of this buffer 336 * using given {@link JsonGenerator}. 337 *<p> 338 * Note: this method would be enough to implement 339 * <code>JsonSerializer</code> for <code>TokenBuffer</code> type; 340 * but we cannot have upwards 341 * references (from core to mapper package); and as such we also 342 * cannot take second argument. 343 */ serialize(JsonGenerator gen)344 public void serialize(JsonGenerator gen) throws IOException 345 { 346 Segment segment = _first; 347 int ptr = -1; 348 349 final boolean checkIds = _mayHaveNativeIds; 350 boolean hasIds = checkIds && (segment.hasIds()); 351 352 while (true) { 353 if (++ptr >= Segment.TOKENS_PER_SEGMENT) { 354 ptr = 0; 355 segment = segment.next(); 356 if (segment == null) break; 357 hasIds = checkIds && (segment.hasIds()); 358 } 359 JsonToken t = segment.type(ptr); 360 if (t == null) break; 361 362 if (hasIds) { 363 Object id = segment.findObjectId(ptr); 364 if (id != null) { 365 gen.writeObjectId(id); 366 } 367 id = segment.findTypeId(ptr); 368 if (id != null) { 369 gen.writeTypeId(id); 370 } 371 } 372 373 // Note: copied from 'copyCurrentEvent'... 374 switch (t) { 375 case START_OBJECT: 376 gen.writeStartObject(); 377 break; 378 case END_OBJECT: 379 gen.writeEndObject(); 380 break; 381 case START_ARRAY: 382 gen.writeStartArray(); 383 break; 384 case END_ARRAY: 385 gen.writeEndArray(); 386 break; 387 case FIELD_NAME: 388 { 389 // 13-Dec-2010, tatu: Maybe we should start using different type tokens to reduce casting? 390 Object ob = segment.get(ptr); 391 if (ob instanceof SerializableString) { 392 gen.writeFieldName((SerializableString) ob); 393 } else { 394 gen.writeFieldName((String) ob); 395 } 396 } 397 break; 398 case VALUE_STRING: 399 { 400 Object ob = segment.get(ptr); 401 if (ob instanceof SerializableString) { 402 gen.writeString((SerializableString) ob); 403 } else { 404 gen.writeString((String) ob); 405 } 406 } 407 break; 408 case VALUE_NUMBER_INT: 409 { 410 Object n = segment.get(ptr); 411 if (n instanceof Integer) { 412 gen.writeNumber((Integer) n); 413 } else if (n instanceof BigInteger) { 414 gen.writeNumber((BigInteger) n); 415 } else if (n instanceof Long) { 416 gen.writeNumber((Long) n); 417 } else if (n instanceof Short) { 418 gen.writeNumber((Short) n); 419 } else { 420 gen.writeNumber(((Number) n).intValue()); 421 } 422 } 423 break; 424 case VALUE_NUMBER_FLOAT: 425 { 426 Object n = segment.get(ptr); 427 if (n instanceof Double) { 428 gen.writeNumber(((Double) n).doubleValue()); 429 } else if (n instanceof BigDecimal) { 430 gen.writeNumber((BigDecimal) n); 431 } else if (n instanceof Float) { 432 gen.writeNumber(((Float) n).floatValue()); 433 } else if (n == null) { 434 gen.writeNull(); 435 } else if (n instanceof String) { 436 gen.writeNumber((String) n); 437 } else { 438 throw new JsonGenerationException(String.format( 439 "Unrecognized value type for VALUE_NUMBER_FLOAT: %s, cannot serialize", 440 n.getClass().getName()), gen); 441 } 442 } 443 break; 444 case VALUE_TRUE: 445 gen.writeBoolean(true); 446 break; 447 case VALUE_FALSE: 448 gen.writeBoolean(false); 449 break; 450 case VALUE_NULL: 451 gen.writeNull(); 452 break; 453 case VALUE_EMBEDDED_OBJECT: 454 { 455 Object value = segment.get(ptr); 456 // 01-Sep-2016, tatu: as per [databind#1361], should use `writeEmbeddedObject()`; 457 // however, may need to consider alternatives for some well-known types 458 // first 459 if (value instanceof RawValue) { 460 ((RawValue) value).serialize(gen); 461 } else if (value instanceof JsonSerializable) { 462 gen.writeObject(value); 463 } else { 464 gen.writeEmbeddedObject(value); 465 } 466 } 467 break; 468 default: 469 throw new RuntimeException("Internal error: should never end up through this code path"); 470 } 471 } 472 } 473 474 /** 475 * Helper method used by standard deserializer. 476 * 477 * @since 2.3 478 */ deserialize(JsonParser p, DeserializationContext ctxt)479 public TokenBuffer deserialize(JsonParser p, DeserializationContext ctxt) throws IOException 480 { 481 if (!p.hasToken(JsonToken.FIELD_NAME)) { 482 copyCurrentStructure(p); 483 return this; 484 } 485 /* 28-Oct-2014, tatu: As per [databind#592], need to support a special case of starting from 486 * FIELD_NAME, which is taken to mean that we are missing START_OBJECT, but need 487 * to assume one did exist. 488 */ 489 JsonToken t; 490 writeStartObject(); 491 do { 492 copyCurrentStructure(p); 493 } while ((t = p.nextToken()) == JsonToken.FIELD_NAME); 494 if (t != JsonToken.END_OBJECT) { 495 ctxt.reportWrongTokenException(TokenBuffer.class, JsonToken.END_OBJECT, 496 "Expected END_OBJECT after copying contents of a JsonParser into TokenBuffer, got "+t); 497 // never gets here 498 } 499 writeEndObject(); 500 return this; 501 } 502 503 @Override 504 @SuppressWarnings("resource") toString()505 public String toString() 506 { 507 // Let's print up to 100 first tokens... 508 final int MAX_COUNT = 100; 509 510 StringBuilder sb = new StringBuilder(); 511 sb.append("[TokenBuffer: "); 512 513 /* 514 sb.append("NativeTypeIds=").append(_hasNativeTypeIds).append(","); 515 sb.append("NativeObjectIds=").append(_hasNativeObjectIds).append(","); 516 */ 517 518 JsonParser jp = asParser(); 519 int count = 0; 520 final boolean hasNativeIds = _hasNativeTypeIds || _hasNativeObjectIds; 521 522 while (true) { 523 JsonToken t; 524 try { 525 t = jp.nextToken(); 526 if (t == null) break; 527 528 if (hasNativeIds) { 529 _appendNativeIds(sb); 530 } 531 532 if (count < MAX_COUNT) { 533 if (count > 0) { 534 sb.append(", "); 535 } 536 sb.append(t.toString()); 537 if (t == JsonToken.FIELD_NAME) { 538 sb.append('('); 539 sb.append(jp.currentName()); 540 sb.append(')'); 541 } 542 } 543 } catch (IOException ioe) { // should never occur 544 throw new IllegalStateException(ioe); 545 } 546 ++count; 547 } 548 549 if (count >= MAX_COUNT) { 550 sb.append(" ... (truncated ").append(count-MAX_COUNT).append(" entries)"); 551 } 552 sb.append(']'); 553 return sb.toString(); 554 } 555 _appendNativeIds(StringBuilder sb)556 private final void _appendNativeIds(StringBuilder sb) 557 { 558 Object objectId = _last.findObjectId(_appendAt-1); 559 if (objectId != null) { 560 sb.append("[objectId=").append(String.valueOf(objectId)).append(']'); 561 } 562 Object typeId = _last.findTypeId(_appendAt-1); 563 if (typeId != null) { 564 sb.append("[typeId=").append(String.valueOf(typeId)).append(']'); 565 } 566 } 567 568 /* 569 /********************************************************** 570 /* JsonGenerator implementation: configuration 571 /********************************************************** 572 */ 573 574 @Override enable(Feature f)575 public JsonGenerator enable(Feature f) { 576 _generatorFeatures |= f.getMask(); 577 return this; 578 } 579 580 @Override disable(Feature f)581 public JsonGenerator disable(Feature f) { 582 _generatorFeatures &= ~f.getMask(); 583 return this; 584 } 585 586 //public JsonGenerator configure(SerializationFeature f, boolean state) { } 587 588 @Override isEnabled(Feature f)589 public boolean isEnabled(Feature f) { 590 return (_generatorFeatures & f.getMask()) != 0; 591 } 592 593 @Override getFeatureMask()594 public int getFeatureMask() { 595 return _generatorFeatures; 596 } 597 598 @Override 599 @Deprecated setFeatureMask(int mask)600 public JsonGenerator setFeatureMask(int mask) { 601 _generatorFeatures = mask; 602 return this; 603 } 604 605 @Override overrideStdFeatures(int values, int mask)606 public JsonGenerator overrideStdFeatures(int values, int mask) { 607 int oldState = getFeatureMask(); 608 _generatorFeatures = (oldState & ~mask) | (values & mask); 609 return this; 610 } 611 612 @Override useDefaultPrettyPrinter()613 public JsonGenerator useDefaultPrettyPrinter() { 614 // No-op: we don't indent 615 return this; 616 } 617 618 @Override setCodec(ObjectCodec oc)619 public JsonGenerator setCodec(ObjectCodec oc) { 620 _objectCodec = oc; 621 return this; 622 } 623 624 @Override getCodec()625 public ObjectCodec getCodec() { return _objectCodec; } 626 627 @Override getOutputContext()628 public final JsonWriteContext getOutputContext() { return _writeContext; } 629 630 /* 631 /********************************************************** 632 /* JsonGenerator implementation: capability introspection 633 /********************************************************** 634 */ 635 636 /** 637 * Since we can efficiently store <code>byte[]</code>, yes. 638 */ 639 @Override canWriteBinaryNatively()640 public boolean canWriteBinaryNatively() { 641 return true; 642 } 643 644 // 20-May-2020, tatu: This may or may not be enough -- ideally access is 645 // via `DeserializationContext`, not parser, but if latter is needed 646 // then we'll need to pass this from parser contents if which were 647 // buffered. 648 @Override getWriteCapabilities()649 public JacksonFeatureSet<StreamWriteCapability> getWriteCapabilities() { 650 return DEFAULT_WRITE_CAPABILITIES; 651 } 652 653 /* 654 /********************************************************** 655 /* JsonGenerator implementation: low-level output handling 656 /********************************************************** 657 */ 658 659 @Override flush()660 public void flush() throws IOException { /* NOP */ } 661 662 @Override close()663 public void close() throws IOException { 664 _closed = true; 665 } 666 667 @Override isClosed()668 public boolean isClosed() { return _closed; } 669 670 /* 671 /********************************************************** 672 /* JsonGenerator implementation: write methods, structural 673 /********************************************************** 674 */ 675 676 @Override writeStartArray()677 public final void writeStartArray() throws IOException 678 { 679 _writeContext.writeValue(); 680 _appendStartMarker(JsonToken.START_ARRAY); 681 _writeContext = _writeContext.createChildArrayContext(); 682 } 683 684 @Override // since 2.10.1 writeStartArray(Object forValue)685 public void writeStartArray(Object forValue) throws IOException { 686 _writeContext.writeValue(); 687 _appendStartMarker(JsonToken.START_ARRAY); 688 _writeContext = _writeContext.createChildArrayContext(forValue); 689 } 690 691 @Override // since 2.10.1 writeStartArray(Object forValue, int size)692 public void writeStartArray(Object forValue, int size) throws IOException { 693 _writeContext.writeValue(); 694 _appendStartMarker(JsonToken.START_ARRAY); 695 _writeContext = _writeContext.createChildArrayContext(forValue); 696 } 697 698 @Override writeEndArray()699 public final void writeEndArray() throws IOException 700 { 701 _appendEndMarker(JsonToken.END_ARRAY); 702 // Let's allow unbalanced tho... i.e. not run out of root level, ever 703 JsonWriteContext c = _writeContext.getParent(); 704 if (c != null) { 705 _writeContext = c; 706 } 707 } 708 709 @Override writeStartObject()710 public final void writeStartObject() throws IOException 711 { 712 _writeContext.writeValue(); 713 _appendStartMarker(JsonToken.START_OBJECT); 714 _writeContext = _writeContext.createChildObjectContext(); 715 } 716 717 @Override // since 2.8 writeStartObject(Object forValue)718 public void writeStartObject(Object forValue) throws IOException 719 { 720 _writeContext.writeValue(); 721 _appendStartMarker(JsonToken.START_OBJECT); 722 JsonWriteContext ctxt = _writeContext.createChildObjectContext(forValue); 723 _writeContext = ctxt; 724 } 725 726 @Override // since 2.10.1 writeStartObject(Object forValue, int size)727 public void writeStartObject(Object forValue, int size) throws IOException 728 { 729 _writeContext.writeValue(); 730 _appendStartMarker(JsonToken.START_OBJECT); 731 JsonWriteContext ctxt = _writeContext.createChildObjectContext(forValue); 732 _writeContext = ctxt; 733 } 734 735 @Override writeEndObject()736 public final void writeEndObject() throws IOException 737 { 738 _appendEndMarker(JsonToken.END_OBJECT); 739 // Let's allow unbalanced tho... i.e. not run out of root level, ever 740 JsonWriteContext c = _writeContext.getParent(); 741 if (c != null) { 742 _writeContext = c; 743 } 744 } 745 746 @Override writeFieldName(String name)747 public final void writeFieldName(String name) throws IOException 748 { 749 _writeContext.writeFieldName(name); 750 _appendFieldName(name); 751 } 752 753 @Override writeFieldName(SerializableString name)754 public void writeFieldName(SerializableString name) throws IOException 755 { 756 _writeContext.writeFieldName(name.getValue()); 757 _appendFieldName(name); 758 } 759 760 /* 761 /********************************************************** 762 /* JsonGenerator implementation: write methods, textual 763 /********************************************************** 764 */ 765 766 @Override writeString(String text)767 public void writeString(String text) throws IOException { 768 if (text == null) { 769 writeNull(); 770 } else { 771 _appendValue(JsonToken.VALUE_STRING, text); 772 } 773 } 774 775 @Override writeString(char[] text, int offset, int len)776 public void writeString(char[] text, int offset, int len) throws IOException { 777 writeString(new String(text, offset, len)); 778 } 779 780 @Override writeString(SerializableString text)781 public void writeString(SerializableString text) throws IOException { 782 if (text == null) { 783 writeNull(); 784 } else { 785 _appendValue(JsonToken.VALUE_STRING, text); 786 } 787 } 788 789 @Override writeRawUTF8String(byte[] text, int offset, int length)790 public void writeRawUTF8String(byte[] text, int offset, int length) throws IOException 791 { 792 // could add support for buffering if we really want it... 793 _reportUnsupportedOperation(); 794 } 795 796 @Override writeUTF8String(byte[] text, int offset, int length)797 public void writeUTF8String(byte[] text, int offset, int length) throws IOException 798 { 799 // could add support for buffering if we really want it... 800 _reportUnsupportedOperation(); 801 } 802 803 @Override writeRaw(String text)804 public void writeRaw(String text) throws IOException { 805 _reportUnsupportedOperation(); 806 } 807 808 @Override writeRaw(String text, int offset, int len)809 public void writeRaw(String text, int offset, int len) throws IOException { 810 _reportUnsupportedOperation(); 811 } 812 813 @Override writeRaw(SerializableString text)814 public void writeRaw(SerializableString text) throws IOException { 815 _reportUnsupportedOperation(); 816 } 817 818 @Override writeRaw(char[] text, int offset, int len)819 public void writeRaw(char[] text, int offset, int len) throws IOException { 820 _reportUnsupportedOperation(); 821 } 822 823 @Override writeRaw(char c)824 public void writeRaw(char c) throws IOException { 825 _reportUnsupportedOperation(); 826 } 827 828 @Override writeRawValue(String text)829 public void writeRawValue(String text) throws IOException { 830 _appendValue(JsonToken.VALUE_EMBEDDED_OBJECT, new RawValue(text)); 831 } 832 833 @Override writeRawValue(String text, int offset, int len)834 public void writeRawValue(String text, int offset, int len) throws IOException { 835 if (offset > 0 || len != text.length()) { 836 text = text.substring(offset, offset+len); 837 } 838 _appendValue(JsonToken.VALUE_EMBEDDED_OBJECT, new RawValue(text)); 839 } 840 841 @Override writeRawValue(char[] text, int offset, int len)842 public void writeRawValue(char[] text, int offset, int len) throws IOException { 843 _appendValue(JsonToken.VALUE_EMBEDDED_OBJECT, new String(text, offset, len)); 844 } 845 846 /* 847 /********************************************************** 848 /* JsonGenerator implementation: write methods, primitive types 849 /********************************************************** 850 */ 851 852 @Override writeNumber(short i)853 public void writeNumber(short i) throws IOException { 854 _appendValue(JsonToken.VALUE_NUMBER_INT, Short.valueOf(i)); 855 } 856 857 @Override writeNumber(int i)858 public void writeNumber(int i) throws IOException { 859 _appendValue(JsonToken.VALUE_NUMBER_INT, Integer.valueOf(i)); 860 } 861 862 @Override writeNumber(long l)863 public void writeNumber(long l) throws IOException { 864 _appendValue(JsonToken.VALUE_NUMBER_INT, Long.valueOf(l)); 865 } 866 867 @Override writeNumber(double d)868 public void writeNumber(double d) throws IOException { 869 _appendValue(JsonToken.VALUE_NUMBER_FLOAT, Double.valueOf(d)); 870 } 871 872 @Override writeNumber(float f)873 public void writeNumber(float f) throws IOException { 874 _appendValue(JsonToken.VALUE_NUMBER_FLOAT, Float.valueOf(f)); 875 } 876 877 @Override writeNumber(BigDecimal dec)878 public void writeNumber(BigDecimal dec) throws IOException { 879 if (dec == null) { 880 writeNull(); 881 } else { 882 _appendValue(JsonToken.VALUE_NUMBER_FLOAT, dec); 883 } 884 } 885 886 @Override writeNumber(BigInteger v)887 public void writeNumber(BigInteger v) throws IOException { 888 if (v == null) { 889 writeNull(); 890 } else { 891 _appendValue(JsonToken.VALUE_NUMBER_INT, v); 892 } 893 } 894 895 @Override writeNumber(String encodedValue)896 public void writeNumber(String encodedValue) throws IOException { 897 /* 03-Dec-2010, tatu: related to [JACKSON-423], should try to keep as numeric 898 * identity as long as possible 899 */ 900 _appendValue(JsonToken.VALUE_NUMBER_FLOAT, encodedValue); 901 } 902 903 @Override writeBoolean(boolean state)904 public void writeBoolean(boolean state) throws IOException { 905 _appendValue(state ? JsonToken.VALUE_TRUE : JsonToken.VALUE_FALSE); 906 } 907 908 @Override writeNull()909 public void writeNull() throws IOException { 910 _appendValue(JsonToken.VALUE_NULL); 911 } 912 913 /* 914 /*********************************************************** 915 /* JsonGenerator implementation: write methods for POJOs/trees 916 /*********************************************************** 917 */ 918 919 @Override writeObject(Object value)920 public void writeObject(Object value) throws IOException 921 { 922 if (value == null) { 923 writeNull(); 924 return; 925 } 926 Class<?> raw = value.getClass(); 927 if (raw == byte[].class || (value instanceof RawValue)) { 928 _appendValue(JsonToken.VALUE_EMBEDDED_OBJECT, value); 929 return; 930 } 931 if (_objectCodec == null) { 932 /* 28-May-2014, tatu: Tricky choice here; if no codec, should we 933 * err out, or just embed? For now, do latter. 934 */ 935 // throw new JsonMappingException("No ObjectCodec configured for TokenBuffer, writeObject() called"); 936 _appendValue(JsonToken.VALUE_EMBEDDED_OBJECT, value); 937 } else { 938 _objectCodec.writeValue(this, value); 939 } 940 } 941 942 @Override writeTree(TreeNode node)943 public void writeTree(TreeNode node) throws IOException 944 { 945 if (node == null) { 946 writeNull(); 947 return; 948 } 949 950 if (_objectCodec == null) { 951 // as with 'writeObject()', is codec optional? 952 _appendValue(JsonToken.VALUE_EMBEDDED_OBJECT, node); 953 } else { 954 _objectCodec.writeTree(this, node); 955 } 956 } 957 958 /* 959 /*********************************************************** 960 /* JsonGenerator implementation; binary 961 /*********************************************************** 962 */ 963 964 @Override writeBinary(Base64Variant b64variant, byte[] data, int offset, int len)965 public void writeBinary(Base64Variant b64variant, byte[] data, int offset, int len) throws IOException 966 { 967 /* 31-Dec-2009, tatu: can do this using multiple alternatives; but for 968 * now, let's try to limit number of conversions. 969 * The only (?) tricky thing is that of whether to preserve variant, 970 * seems pointless, so let's not worry about it unless there's some 971 * compelling reason to. 972 */ 973 byte[] copy = new byte[len]; 974 System.arraycopy(data, offset, copy, 0, len); 975 writeObject(copy); 976 } 977 978 /** 979 * Although we could support this method, it does not necessarily make 980 * sense: we cannot make good use of streaming because buffer must 981 * hold all the data. Because of this, currently this will simply 982 * throw {@link UnsupportedOperationException} 983 */ 984 @Override writeBinary(Base64Variant b64variant, InputStream data, int dataLength)985 public int writeBinary(Base64Variant b64variant, InputStream data, int dataLength) { 986 throw new UnsupportedOperationException(); 987 } 988 989 /* 990 /*********************************************************** 991 /* JsonGenerator implementation: native ids 992 /*********************************************************** 993 */ 994 995 @Override canWriteTypeId()996 public boolean canWriteTypeId() { 997 return _hasNativeTypeIds; 998 } 999 1000 @Override canWriteObjectId()1001 public boolean canWriteObjectId() { 1002 return _hasNativeObjectIds; 1003 } 1004 1005 @Override writeTypeId(Object id)1006 public void writeTypeId(Object id) { 1007 _typeId = id; 1008 _hasNativeId = true; 1009 } 1010 1011 @Override writeObjectId(Object id)1012 public void writeObjectId(Object id) { 1013 _objectId = id; 1014 _hasNativeId = true; 1015 } 1016 1017 @Override // since 2.8 writeEmbeddedObject(Object object)1018 public void writeEmbeddedObject(Object object) throws IOException { 1019 _appendValue(JsonToken.VALUE_EMBEDDED_OBJECT, object); 1020 } 1021 1022 /* 1023 /********************************************************** 1024 /* JsonGenerator implementation; pass-through copy 1025 /********************************************************** 1026 */ 1027 1028 @Override copyCurrentEvent(JsonParser p)1029 public void copyCurrentEvent(JsonParser p) throws IOException 1030 { 1031 if (_mayHaveNativeIds) { 1032 _checkNativeIds(p); 1033 } 1034 switch (p.currentToken()) { 1035 case START_OBJECT: 1036 writeStartObject(); 1037 break; 1038 case END_OBJECT: 1039 writeEndObject(); 1040 break; 1041 case START_ARRAY: 1042 writeStartArray(); 1043 break; 1044 case END_ARRAY: 1045 writeEndArray(); 1046 break; 1047 case FIELD_NAME: 1048 writeFieldName(p.currentName()); 1049 break; 1050 case VALUE_STRING: 1051 if (p.hasTextCharacters()) { 1052 writeString(p.getTextCharacters(), p.getTextOffset(), p.getTextLength()); 1053 } else { 1054 writeString(p.getText()); 1055 } 1056 break; 1057 case VALUE_NUMBER_INT: 1058 switch (p.getNumberType()) { 1059 case INT: 1060 writeNumber(p.getIntValue()); 1061 break; 1062 case BIG_INTEGER: 1063 writeNumber(p.getBigIntegerValue()); 1064 break; 1065 default: 1066 writeNumber(p.getLongValue()); 1067 } 1068 break; 1069 case VALUE_NUMBER_FLOAT: 1070 if (_forceBigDecimal) { 1071 // 10-Oct-2015, tatu: Ideally we would first determine whether underlying 1072 // number is already decoded into a number (in which case might as well 1073 // access as number); or is still retained as text (in which case we 1074 // should further defer decoding that may not need BigDecimal): 1075 writeNumber(p.getDecimalValue()); 1076 } else { 1077 switch (p.getNumberType()) { 1078 case BIG_DECIMAL: 1079 writeNumber(p.getDecimalValue()); 1080 break; 1081 case FLOAT: 1082 writeNumber(p.getFloatValue()); 1083 break; 1084 default: 1085 writeNumber(p.getDoubleValue()); 1086 } 1087 } 1088 break; 1089 case VALUE_TRUE: 1090 writeBoolean(true); 1091 break; 1092 case VALUE_FALSE: 1093 writeBoolean(false); 1094 break; 1095 case VALUE_NULL: 1096 writeNull(); 1097 break; 1098 case VALUE_EMBEDDED_OBJECT: 1099 writeObject(p.getEmbeddedObject()); 1100 break; 1101 default: 1102 throw new RuntimeException("Internal error: unexpected token: "+p.currentToken()); 1103 } 1104 } 1105 1106 @Override copyCurrentStructure(JsonParser p)1107 public void copyCurrentStructure(JsonParser p) throws IOException 1108 { 1109 JsonToken t = p.currentToken(); 1110 1111 // Let's handle field-name separately first 1112 if (t == JsonToken.FIELD_NAME) { 1113 if (_mayHaveNativeIds) { 1114 _checkNativeIds(p); 1115 } 1116 writeFieldName(p.currentName()); 1117 t = p.nextToken(); 1118 // fall-through to copy the associated value 1119 } else if (t == null) { 1120 throw new IllegalStateException("No token available from argument `JsonParser`"); 1121 } 1122 1123 // We'll do minor handling here to separate structured, scalar values, 1124 // then delegate appropriately. 1125 // Plus also deal with oddity of "dangling" END_OBJECT/END_ARRAY 1126 switch (t) { 1127 case START_ARRAY: 1128 if (_mayHaveNativeIds) { 1129 _checkNativeIds(p); 1130 } 1131 writeStartArray(); 1132 _copyBufferContents(p); 1133 break; 1134 case START_OBJECT: 1135 if (_mayHaveNativeIds) { 1136 _checkNativeIds(p); 1137 } 1138 writeStartObject(); 1139 _copyBufferContents(p); 1140 break; 1141 case END_ARRAY: 1142 writeEndArray(); 1143 break; 1144 case END_OBJECT: 1145 writeEndObject(); 1146 break; 1147 default: // others are simple: 1148 _copyBufferValue(p, t); 1149 } 1150 } 1151 _copyBufferContents(JsonParser p)1152 protected void _copyBufferContents(JsonParser p) throws IOException 1153 { 1154 int depth = 1; 1155 JsonToken t; 1156 1157 while ((t = p.nextToken()) != null) { 1158 switch (t) { 1159 case FIELD_NAME: 1160 if (_mayHaveNativeIds) { 1161 _checkNativeIds(p); 1162 } 1163 writeFieldName(p.currentName()); 1164 break; 1165 1166 case START_ARRAY: 1167 if (_mayHaveNativeIds) { 1168 _checkNativeIds(p); 1169 } 1170 writeStartArray(); 1171 ++depth; 1172 break; 1173 1174 case START_OBJECT: 1175 if (_mayHaveNativeIds) { 1176 _checkNativeIds(p); 1177 } 1178 writeStartObject(); 1179 ++depth; 1180 break; 1181 1182 case END_ARRAY: 1183 writeEndArray(); 1184 if (--depth == 0) { 1185 return; 1186 } 1187 break; 1188 case END_OBJECT: 1189 writeEndObject(); 1190 if (--depth == 0) { 1191 return; 1192 } 1193 break; 1194 1195 default: 1196 _copyBufferValue(p, t); 1197 } 1198 } 1199 } 1200 1201 // NOTE: Copied from earlier `copyCurrentEvent()` _copyBufferValue(JsonParser p, JsonToken t)1202 private void _copyBufferValue(JsonParser p, JsonToken t) throws IOException 1203 { 1204 if (_mayHaveNativeIds) { 1205 _checkNativeIds(p); 1206 } 1207 switch (t) { 1208 case VALUE_STRING: 1209 if (p.hasTextCharacters()) { 1210 writeString(p.getTextCharacters(), p.getTextOffset(), p.getTextLength()); 1211 } else { 1212 writeString(p.getText()); 1213 } 1214 break; 1215 case VALUE_NUMBER_INT: 1216 switch (p.getNumberType()) { 1217 case INT: 1218 writeNumber(p.getIntValue()); 1219 break; 1220 case BIG_INTEGER: 1221 writeNumber(p.getBigIntegerValue()); 1222 break; 1223 default: 1224 writeNumber(p.getLongValue()); 1225 } 1226 break; 1227 case VALUE_NUMBER_FLOAT: 1228 if (_forceBigDecimal) { 1229 writeNumber(p.getDecimalValue()); 1230 } else { 1231 // 09-Jul-2020, tatu: Used to just copy using most optimal method, but 1232 // issues like [databind#2644] force to use exact, not optimal type 1233 final Number n = p.getNumberValueExact(); 1234 _appendValue(JsonToken.VALUE_NUMBER_FLOAT, n); 1235 } 1236 break; 1237 case VALUE_TRUE: 1238 writeBoolean(true); 1239 break; 1240 case VALUE_FALSE: 1241 writeBoolean(false); 1242 break; 1243 case VALUE_NULL: 1244 writeNull(); 1245 break; 1246 case VALUE_EMBEDDED_OBJECT: 1247 writeObject(p.getEmbeddedObject()); 1248 break; 1249 default: 1250 throw new RuntimeException("Internal error: unexpected token: "+t); 1251 } 1252 } 1253 _checkNativeIds(JsonParser p)1254 private final void _checkNativeIds(JsonParser p) throws IOException 1255 { 1256 if ((_typeId = p.getTypeId()) != null) { 1257 _hasNativeId = true; 1258 } 1259 if ((_objectId = p.getObjectId()) != null) { 1260 _hasNativeId = true; 1261 } 1262 } 1263 1264 /* 1265 /********************************************************** 1266 /* Internal methods 1267 /********************************************************** 1268 */ 1269 1270 /*// Not used in / since 2.10 1271 protected final void _append(JsonToken type) 1272 { 1273 Segment next; 1274 1275 if (_hasNativeId) { 1276 next =_last.append(_appendAt, type, _objectId, _typeId); 1277 } else { 1278 next = _last.append(_appendAt, type); 1279 } 1280 if (next == null) { 1281 ++_appendAt; 1282 } else { 1283 _last = next; 1284 _appendAt = 1; // since we added first at 0 1285 } 1286 } 1287 1288 protected final void _append(JsonToken type, Object value) 1289 { 1290 Segment next; 1291 if (_hasNativeId) { 1292 next = _last.append(_appendAt, type, value, _objectId, _typeId); 1293 } else { 1294 next = _last.append(_appendAt, type, value); 1295 } 1296 if (next == null) { 1297 ++_appendAt; 1298 } else { 1299 _last = next; 1300 _appendAt = 1; 1301 } 1302 } 1303 */ 1304 1305 /** 1306 * Method used for appending token known to represent a "simple" scalar 1307 * value where token is the only information 1308 * 1309 * @since 2.6.4 1310 */ _appendValue(JsonToken type)1311 protected final void _appendValue(JsonToken type) 1312 { 1313 _writeContext.writeValue(); 1314 Segment next; 1315 if (_hasNativeId) { 1316 next = _last.append(_appendAt, type, _objectId, _typeId); 1317 } else { 1318 next = _last.append(_appendAt, type); 1319 } 1320 if (next == null) { 1321 ++_appendAt; 1322 } else { 1323 _last = next; 1324 _appendAt = 1; // since we added first at 0 1325 } 1326 } 1327 1328 /** 1329 * Method used for appending token known to represent a scalar value 1330 * where there is additional content (text, number) beyond type token 1331 * 1332 * @since 2.6.4 1333 */ _appendValue(JsonToken type, Object value)1334 protected final void _appendValue(JsonToken type, Object value) 1335 { 1336 _writeContext.writeValue(); 1337 Segment next; 1338 if (_hasNativeId) { 1339 next = _last.append(_appendAt, type, value, _objectId, _typeId); 1340 } else { 1341 next = _last.append(_appendAt, type, value); 1342 } 1343 if (next == null) { 1344 ++_appendAt; 1345 } else { 1346 _last = next; 1347 _appendAt = 1; 1348 } 1349 } 1350 1351 /** 1352 * Specialized method used for appending a field name, appending either 1353 * {@link String} or {@link SerializableString}. 1354 * 1355 * @since 2.10 1356 */ _appendFieldName(Object value)1357 protected final void _appendFieldName(Object value) 1358 { 1359 // NOTE: do NOT clear _objectId / _typeId 1360 Segment next; 1361 if (_hasNativeId) { 1362 next = _last.append(_appendAt, JsonToken.FIELD_NAME, value, _objectId, _typeId); 1363 } else { 1364 next = _last.append(_appendAt, JsonToken.FIELD_NAME, value); 1365 } 1366 if (next == null) { 1367 ++_appendAt; 1368 } else { 1369 _last = next; 1370 _appendAt = 1; 1371 } 1372 } 1373 1374 /** 1375 * Specialized method used for appending a structural start Object/Array marker 1376 * 1377 * @since 2.10 1378 */ _appendStartMarker(JsonToken type)1379 protected final void _appendStartMarker(JsonToken type) 1380 { 1381 Segment next; 1382 if (_hasNativeId) { 1383 next =_last.append(_appendAt, type, _objectId, _typeId); 1384 } else { 1385 next = _last.append(_appendAt, type); 1386 } 1387 if (next == null) { 1388 ++_appendAt; 1389 } else { 1390 _last = next; 1391 _appendAt = 1; // since we added first at 0 1392 } 1393 } 1394 1395 /** 1396 * Specialized method used for appending a structural end Object/Array marker 1397 * 1398 * @since 2.10 1399 */ _appendEndMarker(JsonToken type)1400 protected final void _appendEndMarker(JsonToken type) 1401 { 1402 // NOTE: type/object id not relevant 1403 Segment next = _last.append(_appendAt, type); 1404 if (next == null) { 1405 ++_appendAt; 1406 } else { 1407 _last = next; 1408 _appendAt = 1; 1409 } 1410 } 1411 1412 @Override _reportUnsupportedOperation()1413 protected void _reportUnsupportedOperation() { 1414 throw new UnsupportedOperationException("Called operation not supported for TokenBuffer"); 1415 } 1416 1417 /* 1418 /********************************************************** 1419 /* Supporting classes 1420 /********************************************************** 1421 */ 1422 1423 protected final static class Parser 1424 extends ParserMinimalBase 1425 { 1426 /* 1427 /********************************************************** 1428 /* Configuration 1429 /********************************************************** 1430 */ 1431 1432 protected ObjectCodec _codec; 1433 1434 /** 1435 * @since 2.3 1436 */ 1437 protected final boolean _hasNativeTypeIds; 1438 1439 /** 1440 * @since 2.3 1441 */ 1442 protected final boolean _hasNativeObjectIds; 1443 1444 protected final boolean _hasNativeIds; 1445 1446 /* 1447 /********************************************************** 1448 /* Parsing state 1449 /********************************************************** 1450 */ 1451 1452 /** 1453 * Currently active segment 1454 */ 1455 protected Segment _segment; 1456 1457 /** 1458 * Pointer to current token within current segment 1459 */ 1460 protected int _segmentPtr; 1461 1462 /** 1463 * Information about parser context, context in which 1464 * the next token is to be parsed (root, array, object). 1465 */ 1466 protected TokenBufferReadContext _parsingContext; 1467 1468 protected boolean _closed; 1469 1470 protected transient ByteArrayBuilder _byteBuilder; 1471 1472 protected JsonLocation _location = null; 1473 1474 /* 1475 /********************************************************** 1476 /* Construction, init 1477 /********************************************************** 1478 */ 1479 1480 @Deprecated // since 2.9 Parser(Segment firstSeg, ObjectCodec codec, boolean hasNativeTypeIds, boolean hasNativeObjectIds)1481 public Parser(Segment firstSeg, ObjectCodec codec, 1482 boolean hasNativeTypeIds, boolean hasNativeObjectIds) 1483 { 1484 this(firstSeg, codec, hasNativeTypeIds, hasNativeObjectIds, null); 1485 } 1486 Parser(Segment firstSeg, ObjectCodec codec, boolean hasNativeTypeIds, boolean hasNativeObjectIds, JsonStreamContext parentContext)1487 public Parser(Segment firstSeg, ObjectCodec codec, 1488 boolean hasNativeTypeIds, boolean hasNativeObjectIds, 1489 JsonStreamContext parentContext) 1490 { 1491 super(0); 1492 _segment = firstSeg; 1493 _segmentPtr = -1; // not yet read 1494 _codec = codec; 1495 _parsingContext = TokenBufferReadContext.createRootContext(parentContext); 1496 _hasNativeTypeIds = hasNativeTypeIds; 1497 _hasNativeObjectIds = hasNativeObjectIds; 1498 _hasNativeIds = (hasNativeTypeIds | hasNativeObjectIds); 1499 } 1500 setLocation(JsonLocation l)1501 public void setLocation(JsonLocation l) { 1502 _location = l; 1503 } 1504 1505 @Override getCodec()1506 public ObjectCodec getCodec() { return _codec; } 1507 1508 @Override setCodec(ObjectCodec c)1509 public void setCodec(ObjectCodec c) { _codec = c; } 1510 1511 /* 1512 /********************************************************** 1513 /* Public API, config access, capability introspection 1514 /********************************************************** 1515 */ 1516 1517 @Override version()1518 public Version version() { 1519 return com.fasterxml.jackson.databind.cfg.PackageVersion.VERSION; 1520 } 1521 1522 // 20-May-2020, tatu: This may or may not be enough -- ideally access is 1523 // via `DeserializationContext`, not parser, but if latter is needed 1524 // then we'll need to pass this from parser contents if which were 1525 // buffered. 1526 @Override getReadCapabilities()1527 public JacksonFeatureSet<StreamReadCapability> getReadCapabilities() { 1528 return DEFAULT_READ_CAPABILITIES; 1529 } 1530 1531 /* 1532 /********************************************************** 1533 /* Extended API beyond JsonParser 1534 /********************************************************** 1535 */ 1536 peekNextToken()1537 public JsonToken peekNextToken() throws IOException 1538 { 1539 // closed? nothing more to peek, either 1540 if (_closed) return null; 1541 Segment seg = _segment; 1542 int ptr = _segmentPtr+1; 1543 if (ptr >= Segment.TOKENS_PER_SEGMENT) { 1544 ptr = 0; 1545 seg = (seg == null) ? null : seg.next(); 1546 } 1547 return (seg == null) ? null : seg.type(ptr); 1548 } 1549 1550 /* 1551 /********************************************************** 1552 /* Closeable implementation 1553 /********************************************************** 1554 */ 1555 1556 @Override close()1557 public void close() throws IOException { 1558 if (!_closed) { 1559 _closed = true; 1560 } 1561 } 1562 1563 /* 1564 /********************************************************** 1565 /* Public API, traversal 1566 /********************************************************** 1567 */ 1568 1569 @Override nextToken()1570 public JsonToken nextToken() throws IOException 1571 { 1572 // If we are closed, nothing more to do 1573 if (_closed || (_segment == null)) return null; 1574 1575 // Ok, then: any more tokens? 1576 if (++_segmentPtr >= Segment.TOKENS_PER_SEGMENT) { 1577 _segmentPtr = 0; 1578 _segment = _segment.next(); 1579 if (_segment == null) { 1580 return null; 1581 } 1582 } 1583 _currToken = _segment.type(_segmentPtr); 1584 // Field name? Need to update context 1585 if (_currToken == JsonToken.FIELD_NAME) { 1586 Object ob = _currentObject(); 1587 String name = (ob instanceof String) ? ((String) ob) : ob.toString(); 1588 _parsingContext.setCurrentName(name); 1589 } else if (_currToken == JsonToken.START_OBJECT) { 1590 _parsingContext = _parsingContext.createChildObjectContext(); 1591 } else if (_currToken == JsonToken.START_ARRAY) { 1592 _parsingContext = _parsingContext.createChildArrayContext(); 1593 } else if (_currToken == JsonToken.END_OBJECT 1594 || _currToken == JsonToken.END_ARRAY) { 1595 // Closing JSON Object/Array? Close matching context 1596 _parsingContext = _parsingContext.parentOrCopy(); 1597 } else { 1598 _parsingContext.updateForValue(); 1599 } 1600 return _currToken; 1601 } 1602 1603 @Override nextFieldName()1604 public String nextFieldName() throws IOException 1605 { 1606 // inlined common case from nextToken() 1607 if (_closed || (_segment == null)) { 1608 return null; 1609 } 1610 1611 int ptr = _segmentPtr+1; 1612 if ((ptr < Segment.TOKENS_PER_SEGMENT) && (_segment.type(ptr) == JsonToken.FIELD_NAME)) { 1613 _segmentPtr = ptr; 1614 _currToken = JsonToken.FIELD_NAME; 1615 Object ob = _segment.get(ptr); // inlined _currentObject(); 1616 String name = (ob instanceof String) ? ((String) ob) : ob.toString(); 1617 _parsingContext.setCurrentName(name); 1618 return name; 1619 } 1620 return (nextToken() == JsonToken.FIELD_NAME) ? currentName() : null; 1621 } 1622 1623 @Override isClosed()1624 public boolean isClosed() { return _closed; } 1625 1626 /* 1627 /********************************************************** 1628 /* Public API, token accessors 1629 /********************************************************** 1630 */ 1631 1632 @Override getParsingContext()1633 public JsonStreamContext getParsingContext() { return _parsingContext; } 1634 1635 @Override getTokenLocation()1636 public JsonLocation getTokenLocation() { return getCurrentLocation(); } 1637 1638 @Override getCurrentLocation()1639 public JsonLocation getCurrentLocation() { 1640 return (_location == null) ? JsonLocation.NA : _location; 1641 } 1642 1643 @Override currentName()1644 public String currentName() { 1645 // 25-Jun-2015, tatu: as per [databind#838], needs to be same as ParserBase 1646 if (_currToken == JsonToken.START_OBJECT || _currToken == JsonToken.START_ARRAY) { 1647 JsonStreamContext parent = _parsingContext.getParent(); 1648 return parent.getCurrentName(); 1649 } 1650 return _parsingContext.getCurrentName(); 1651 } 1652 1653 @Override // since 2.12 delegate to the new method getCurrentName()1654 public String getCurrentName() { return currentName(); } 1655 1656 @Override overrideCurrentName(String name)1657 public void overrideCurrentName(String name) 1658 { 1659 // Simple, but need to look for START_OBJECT/ARRAY's "off-by-one" thing: 1660 JsonStreamContext ctxt = _parsingContext; 1661 if (_currToken == JsonToken.START_OBJECT || _currToken == JsonToken.START_ARRAY) { 1662 ctxt = ctxt.getParent(); 1663 } 1664 if (ctxt instanceof TokenBufferReadContext) { 1665 try { 1666 ((TokenBufferReadContext) ctxt).setCurrentName(name); 1667 } catch (IOException e) { 1668 throw new RuntimeException(e); 1669 } 1670 } 1671 } 1672 1673 /* 1674 /********************************************************** 1675 /* Public API, access to token information, text 1676 /********************************************************** 1677 */ 1678 1679 @Override getText()1680 public String getText() 1681 { 1682 // common cases first: 1683 if (_currToken == JsonToken.VALUE_STRING 1684 || _currToken == JsonToken.FIELD_NAME) { 1685 Object ob = _currentObject(); 1686 if (ob instanceof String) { 1687 return (String) ob; 1688 } 1689 return ClassUtil.nullOrToString(ob); 1690 } 1691 if (_currToken == null) { 1692 return null; 1693 } 1694 switch (_currToken) { 1695 case VALUE_NUMBER_INT: 1696 case VALUE_NUMBER_FLOAT: 1697 return ClassUtil.nullOrToString(_currentObject()); 1698 default: 1699 return _currToken.asString(); 1700 } 1701 } 1702 1703 @Override getTextCharacters()1704 public char[] getTextCharacters() { 1705 String str = getText(); 1706 return (str == null) ? null : str.toCharArray(); 1707 } 1708 1709 @Override getTextLength()1710 public int getTextLength() { 1711 String str = getText(); 1712 return (str == null) ? 0 : str.length(); 1713 } 1714 1715 @Override getTextOffset()1716 public int getTextOffset() { return 0; } 1717 1718 @Override hasTextCharacters()1719 public boolean hasTextCharacters() { 1720 // We never have raw buffer available, so: 1721 return false; 1722 } 1723 1724 /* 1725 /********************************************************** 1726 /* Public API, access to token information, numeric 1727 /********************************************************** 1728 */ 1729 1730 @Override isNaN()1731 public boolean isNaN() { 1732 // can only occur for floating-point numbers 1733 if (_currToken == JsonToken.VALUE_NUMBER_FLOAT) { 1734 Object value = _currentObject(); 1735 if (value instanceof Double) { 1736 Double v = (Double) value; 1737 return v.isNaN() || v.isInfinite(); 1738 } 1739 if (value instanceof Float) { 1740 Float v = (Float) value; 1741 return v.isNaN() || v.isInfinite(); 1742 } 1743 } 1744 return false; 1745 } 1746 1747 @Override getBigIntegerValue()1748 public BigInteger getBigIntegerValue() throws IOException 1749 { 1750 Number n = getNumberValue(); 1751 if (n instanceof BigInteger) { 1752 return (BigInteger) n; 1753 } 1754 if (getNumberType() == NumberType.BIG_DECIMAL) { 1755 return ((BigDecimal) n).toBigInteger(); 1756 } 1757 // int/long is simple, but let's also just truncate float/double: 1758 return BigInteger.valueOf(n.longValue()); 1759 } 1760 1761 @Override getDecimalValue()1762 public BigDecimal getDecimalValue() throws IOException 1763 { 1764 Number n = getNumberValue(); 1765 if (n instanceof BigDecimal) { 1766 return (BigDecimal) n; 1767 } 1768 switch (getNumberType()) { 1769 case INT: 1770 case LONG: 1771 return BigDecimal.valueOf(n.longValue()); 1772 case BIG_INTEGER: 1773 return new BigDecimal((BigInteger) n); 1774 default: 1775 } 1776 // float or double 1777 return BigDecimal.valueOf(n.doubleValue()); 1778 } 1779 1780 @Override getDoubleValue()1781 public double getDoubleValue() throws IOException { 1782 return getNumberValue().doubleValue(); 1783 } 1784 1785 @Override getFloatValue()1786 public float getFloatValue() throws IOException { 1787 return getNumberValue().floatValue(); 1788 } 1789 1790 @Override getIntValue()1791 public int getIntValue() throws IOException 1792 { 1793 Number n = (_currToken == JsonToken.VALUE_NUMBER_INT) ? 1794 ((Number) _currentObject()) : getNumberValue(); 1795 if ((n instanceof Integer) || _smallerThanInt(n)) { 1796 return n.intValue(); 1797 } 1798 return _convertNumberToInt(n); 1799 } 1800 1801 @Override getLongValue()1802 public long getLongValue() throws IOException { 1803 Number n = (_currToken == JsonToken.VALUE_NUMBER_INT) ? 1804 ((Number) _currentObject()) : getNumberValue(); 1805 if ((n instanceof Long) || _smallerThanLong(n)) { 1806 return n.longValue(); 1807 } 1808 return _convertNumberToLong(n); 1809 } 1810 1811 @Override getNumberType()1812 public NumberType getNumberType() throws IOException 1813 { 1814 Number n = getNumberValue(); 1815 if (n instanceof Integer) return NumberType.INT; 1816 if (n instanceof Long) return NumberType.LONG; 1817 if (n instanceof Double) return NumberType.DOUBLE; 1818 if (n instanceof BigDecimal) return NumberType.BIG_DECIMAL; 1819 if (n instanceof BigInteger) return NumberType.BIG_INTEGER; 1820 if (n instanceof Float) return NumberType.FLOAT; 1821 if (n instanceof Short) return NumberType.INT; // should be SHORT 1822 return null; 1823 } 1824 1825 @Override getNumberValue()1826 public final Number getNumberValue() throws IOException { 1827 _checkIsNumber(); 1828 Object value = _currentObject(); 1829 if (value instanceof Number) { 1830 return (Number) value; 1831 } 1832 // Difficult to really support numbers-as-Strings; but let's try. 1833 // NOTE: no access to DeserializationConfig, unfortunately, so cannot 1834 // try to determine Double/BigDecimal preference... 1835 if (value instanceof String) { 1836 String str = (String) value; 1837 if (str.indexOf('.') >= 0) { 1838 return Double.parseDouble(str); 1839 } 1840 return Long.parseLong(str); 1841 } 1842 if (value == null) { 1843 return null; 1844 } 1845 throw new IllegalStateException("Internal error: entry should be a Number, but is of type " 1846 +value.getClass().getName()); 1847 } 1848 _smallerThanInt(Number n)1849 private final boolean _smallerThanInt(Number n) { 1850 return (n instanceof Short) || (n instanceof Byte); 1851 } 1852 _smallerThanLong(Number n)1853 private final boolean _smallerThanLong(Number n) { 1854 return (n instanceof Integer) || (n instanceof Short) || (n instanceof Byte); 1855 } 1856 1857 // 02-Jan-2017, tatu: Modified from method(s) in `ParserBase` 1858 _convertNumberToInt(Number n)1859 protected int _convertNumberToInt(Number n) throws IOException 1860 { 1861 if (n instanceof Long) { 1862 long l = n.longValue(); 1863 int result = (int) l; 1864 if (((long) result) != l) { 1865 reportOverflowInt(); 1866 } 1867 return result; 1868 } 1869 if (n instanceof BigInteger) { 1870 BigInteger big = (BigInteger) n; 1871 if (BI_MIN_INT.compareTo(big) > 0 1872 || BI_MAX_INT.compareTo(big) < 0) { 1873 reportOverflowInt(); 1874 } 1875 } else if ((n instanceof Double) || (n instanceof Float)) { 1876 double d = n.doubleValue(); 1877 // Need to check boundaries 1878 if (d < MIN_INT_D || d > MAX_INT_D) { 1879 reportOverflowInt(); 1880 } 1881 return (int) d; 1882 } else if (n instanceof BigDecimal) { 1883 BigDecimal big = (BigDecimal) n; 1884 if (BD_MIN_INT.compareTo(big) > 0 1885 || BD_MAX_INT.compareTo(big) < 0) { 1886 reportOverflowInt(); 1887 } 1888 } else { 1889 _throwInternal(); 1890 } 1891 return n.intValue(); 1892 } 1893 _convertNumberToLong(Number n)1894 protected long _convertNumberToLong(Number n) throws IOException 1895 { 1896 if (n instanceof BigInteger) { 1897 BigInteger big = (BigInteger) n; 1898 if (BI_MIN_LONG.compareTo(big) > 0 1899 || BI_MAX_LONG.compareTo(big) < 0) { 1900 reportOverflowLong(); 1901 } 1902 } else if ((n instanceof Double) || (n instanceof Float)) { 1903 double d = n.doubleValue(); 1904 // Need to check boundaries 1905 if (d < MIN_LONG_D || d > MAX_LONG_D) { 1906 reportOverflowLong(); 1907 } 1908 return (long) d; 1909 } else if (n instanceof BigDecimal) { 1910 BigDecimal big = (BigDecimal) n; 1911 if (BD_MIN_LONG.compareTo(big) > 0 1912 || BD_MAX_LONG.compareTo(big) < 0) { 1913 reportOverflowLong(); 1914 } 1915 } else { 1916 _throwInternal(); 1917 } 1918 return n.longValue(); 1919 } 1920 1921 /* 1922 /********************************************************** 1923 /* Public API, access to token information, other 1924 /********************************************************** 1925 */ 1926 1927 @Override getEmbeddedObject()1928 public Object getEmbeddedObject() 1929 { 1930 if (_currToken == JsonToken.VALUE_EMBEDDED_OBJECT) { 1931 return _currentObject(); 1932 } 1933 return null; 1934 } 1935 1936 @Override 1937 @SuppressWarnings("resource") getBinaryValue(Base64Variant b64variant)1938 public byte[] getBinaryValue(Base64Variant b64variant) throws IOException, JsonParseException 1939 { 1940 // First: maybe we some special types? 1941 if (_currToken == JsonToken.VALUE_EMBEDDED_OBJECT) { 1942 // Embedded byte array would work nicely... 1943 Object ob = _currentObject(); 1944 if (ob instanceof byte[]) { 1945 return (byte[]) ob; 1946 } 1947 // fall through to error case 1948 } 1949 if (_currToken != JsonToken.VALUE_STRING) { 1950 throw _constructError("Current token ("+_currToken+") not VALUE_STRING (or VALUE_EMBEDDED_OBJECT with byte[]), cannot access as binary"); 1951 } 1952 final String str = getText(); 1953 if (str == null) { 1954 return null; 1955 } 1956 ByteArrayBuilder builder = _byteBuilder; 1957 if (builder == null) { 1958 _byteBuilder = builder = new ByteArrayBuilder(100); 1959 } else { 1960 _byteBuilder.reset(); 1961 } 1962 _decodeBase64(str, builder, b64variant); 1963 return builder.toByteArray(); 1964 } 1965 1966 @Override readBinaryValue(Base64Variant b64variant, OutputStream out)1967 public int readBinaryValue(Base64Variant b64variant, OutputStream out) throws IOException 1968 { 1969 byte[] data = getBinaryValue(b64variant); 1970 if (data != null) { 1971 out.write(data, 0, data.length); 1972 return data.length; 1973 } 1974 return 0; 1975 } 1976 1977 /* 1978 /********************************************************** 1979 /* Public API, native ids 1980 /********************************************************** 1981 */ 1982 1983 @Override canReadObjectId()1984 public boolean canReadObjectId() { 1985 return _hasNativeObjectIds; 1986 } 1987 1988 @Override canReadTypeId()1989 public boolean canReadTypeId() { 1990 return _hasNativeTypeIds; 1991 } 1992 1993 @Override getTypeId()1994 public Object getTypeId() { 1995 return _segment.findTypeId(_segmentPtr); 1996 } 1997 1998 @Override getObjectId()1999 public Object getObjectId() { 2000 return _segment.findObjectId(_segmentPtr); 2001 } 2002 2003 /* 2004 /********************************************************** 2005 /* Internal methods 2006 /********************************************************** 2007 */ 2008 _currentObject()2009 protected final Object _currentObject() { 2010 return _segment.get(_segmentPtr); 2011 } 2012 _checkIsNumber()2013 protected final void _checkIsNumber() throws JsonParseException 2014 { 2015 if (_currToken == null || !_currToken.isNumeric()) { 2016 throw _constructError("Current token ("+_currToken+") not numeric, cannot use numeric value accessors"); 2017 } 2018 } 2019 2020 @Override _handleEOF()2021 protected void _handleEOF() throws JsonParseException { 2022 _throwInternal(); 2023 } 2024 } 2025 2026 /** 2027 * Individual segment of TokenBuffer that can store up to 16 tokens 2028 * (limited by 4 bits per token type marker requirement). 2029 * Current implementation uses fixed length array; could alternatively 2030 * use 16 distinct fields and switch statement (slightly more efficient 2031 * storage, slightly slower access) 2032 */ 2033 protected final static class Segment 2034 { 2035 public final static int TOKENS_PER_SEGMENT = 16; 2036 2037 /** 2038 * Static array used for fast conversion between token markers and 2039 * matching {@link JsonToken} instances 2040 */ 2041 private final static JsonToken[] TOKEN_TYPES_BY_INDEX; 2042 static { 2043 // ... here we know that there are <= 15 values in JsonToken enum 2044 TOKEN_TYPES_BY_INDEX = new JsonToken[16]; 2045 JsonToken[] t = JsonToken.values(); 2046 // and reserve entry 0 for "not available" System.arraycopy(t, 1, TOKEN_TYPES_BY_INDEX, 1, Math.min(15, t.length - 1))2047 System.arraycopy(t, 1, TOKEN_TYPES_BY_INDEX, 1, Math.min(15, t.length - 1)); 2048 } 2049 2050 // // // Linking 2051 2052 protected Segment _next; 2053 2054 // // // State 2055 2056 /** 2057 * Bit field used to store types of buffered tokens; 4 bits per token. 2058 * Value 0 is reserved for "not in use" 2059 */ 2060 protected long _tokenTypes; 2061 2062 2063 // Actual tokens 2064 2065 protected final Object[] _tokens = new Object[TOKENS_PER_SEGMENT]; 2066 2067 /** 2068 * Lazily constructed Map for storing native type and object ids, if any 2069 */ 2070 protected TreeMap<Integer,Object> _nativeIds; 2071 Segment()2072 public Segment() { } 2073 2074 // // // Accessors 2075 type(int index)2076 public JsonToken type(int index) 2077 { 2078 long l = _tokenTypes; 2079 if (index > 0) { 2080 l >>= (index << 2); 2081 } 2082 int ix = ((int) l) & 0xF; 2083 return TOKEN_TYPES_BY_INDEX[ix]; 2084 } 2085 rawType(int index)2086 public int rawType(int index) 2087 { 2088 long l = _tokenTypes; 2089 if (index > 0) { 2090 l >>= (index << 2); 2091 } 2092 int ix = ((int) l) & 0xF; 2093 return ix; 2094 } 2095 get(int index)2096 public Object get(int index) { 2097 return _tokens[index]; 2098 } 2099 next()2100 public Segment next() { return _next; } 2101 2102 /** 2103 * Accessor for checking whether this segment may have native 2104 * type or object ids. 2105 */ hasIds()2106 public boolean hasIds() { 2107 return _nativeIds != null; 2108 } 2109 2110 // // // Mutators 2111 append(int index, JsonToken tokenType)2112 public Segment append(int index, JsonToken tokenType) 2113 { 2114 if (index < TOKENS_PER_SEGMENT) { 2115 set(index, tokenType); 2116 return null; 2117 } 2118 _next = new Segment(); 2119 _next.set(0, tokenType); 2120 return _next; 2121 } 2122 append(int index, JsonToken tokenType, Object objectId, Object typeId)2123 public Segment append(int index, JsonToken tokenType, 2124 Object objectId, Object typeId) 2125 { 2126 if (index < TOKENS_PER_SEGMENT) { 2127 set(index, tokenType, objectId, typeId); 2128 return null; 2129 } 2130 _next = new Segment(); 2131 _next.set(0, tokenType, objectId, typeId); 2132 return _next; 2133 } 2134 append(int index, JsonToken tokenType, Object value)2135 public Segment append(int index, JsonToken tokenType, Object value) 2136 { 2137 if (index < TOKENS_PER_SEGMENT) { 2138 set(index, tokenType, value); 2139 return null; 2140 } 2141 _next = new Segment(); 2142 _next.set(0, tokenType, value); 2143 return _next; 2144 } 2145 append(int index, JsonToken tokenType, Object value, Object objectId, Object typeId)2146 public Segment append(int index, JsonToken tokenType, Object value, 2147 Object objectId, Object typeId) 2148 { 2149 if (index < TOKENS_PER_SEGMENT) { 2150 set(index, tokenType, value, objectId, typeId); 2151 return null; 2152 } 2153 _next = new Segment(); 2154 _next.set(0, tokenType, value, objectId, typeId); 2155 return _next; 2156 } 2157 2158 /* 2159 public Segment appendRaw(int index, int rawTokenType, Object value) 2160 { 2161 if (index < TOKENS_PER_SEGMENT) { 2162 set(index, rawTokenType, value); 2163 return null; 2164 } 2165 _next = new Segment(); 2166 _next.set(0, rawTokenType, value); 2167 return _next; 2168 } 2169 2170 public Segment appendRaw(int index, int rawTokenType, Object value, 2171 Object objectId, Object typeId) 2172 { 2173 if (index < TOKENS_PER_SEGMENT) { 2174 set(index, rawTokenType, value, objectId, typeId); 2175 return null; 2176 } 2177 _next = new Segment(); 2178 _next.set(0, rawTokenType, value, objectId, typeId); 2179 return _next; 2180 } 2181 2182 private void set(int index, int rawTokenType, Object value, Object objectId, Object typeId) 2183 { 2184 _tokens[index] = value; 2185 long typeCode = (long) rawTokenType; 2186 if (index > 0) { 2187 typeCode <<= (index << 2); 2188 } 2189 _tokenTypes |= typeCode; 2190 assignNativeIds(index, objectId, typeId); 2191 } 2192 2193 private void set(int index, int rawTokenType, Object value) 2194 { 2195 _tokens[index] = value; 2196 long typeCode = (long) rawTokenType; 2197 if (index > 0) { 2198 typeCode <<= (index << 2); 2199 } 2200 _tokenTypes |= typeCode; 2201 } 2202 */ 2203 set(int index, JsonToken tokenType)2204 private void set(int index, JsonToken tokenType) 2205 { 2206 /* Assumption here is that there are no overwrites, just appends; 2207 * and so no masking is needed (nor explicit setting of null) 2208 */ 2209 long typeCode = tokenType.ordinal(); 2210 if (index > 0) { 2211 typeCode <<= (index << 2); 2212 } 2213 _tokenTypes |= typeCode; 2214 } 2215 set(int index, JsonToken tokenType, Object objectId, Object typeId)2216 private void set(int index, JsonToken tokenType, 2217 Object objectId, Object typeId) 2218 { 2219 long typeCode = tokenType.ordinal(); 2220 if (index > 0) { 2221 typeCode <<= (index << 2); 2222 } 2223 _tokenTypes |= typeCode; 2224 assignNativeIds(index, objectId, typeId); 2225 } 2226 set(int index, JsonToken tokenType, Object value)2227 private void set(int index, JsonToken tokenType, Object value) 2228 { 2229 _tokens[index] = value; 2230 long typeCode = tokenType.ordinal(); 2231 if (index > 0) { 2232 typeCode <<= (index << 2); 2233 } 2234 _tokenTypes |= typeCode; 2235 } 2236 set(int index, JsonToken tokenType, Object value, Object objectId, Object typeId)2237 private void set(int index, JsonToken tokenType, Object value, 2238 Object objectId, Object typeId) 2239 { 2240 _tokens[index] = value; 2241 long typeCode = tokenType.ordinal(); 2242 if (index > 0) { 2243 typeCode <<= (index << 2); 2244 } 2245 _tokenTypes |= typeCode; 2246 assignNativeIds(index, objectId, typeId); 2247 } 2248 assignNativeIds(int index, Object objectId, Object typeId)2249 private final void assignNativeIds(int index, Object objectId, Object typeId) 2250 { 2251 if (_nativeIds == null) { 2252 _nativeIds = new TreeMap<Integer,Object>(); 2253 } 2254 if (objectId != null) { 2255 _nativeIds.put(_objectIdIndex(index), objectId); 2256 } 2257 if (typeId != null) { 2258 _nativeIds.put(_typeIdIndex(index), typeId); 2259 } 2260 } 2261 2262 /** 2263 * @since 2.3 2264 */ findObjectId(int index)2265 private Object findObjectId(int index) { 2266 return (_nativeIds == null) ? null : _nativeIds.get(_objectIdIndex(index)); 2267 } 2268 2269 /** 2270 * @since 2.3 2271 */ findTypeId(int index)2272 private Object findTypeId(int index) { 2273 return (_nativeIds == null) ? null : _nativeIds.get(_typeIdIndex(index)); 2274 } 2275 _typeIdIndex(int i)2276 private final int _typeIdIndex(int i) { return i+i; } _objectIdIndex(int i)2277 private final int _objectIdIndex(int i) { return i+i+1; } 2278 } 2279 } 2280