@@ -2477,6 +2477,7 @@ public void copyCurrentEvent(JsonParser p) throws IOException
2477
2477
_copyCurrentIntValue (p );
2478
2478
break ;
2479
2479
case ID_NUMBER_FLOAT :
2480
+ // Different from "copyCurrentEventExact"!
2480
2481
_copyCurrentFloatValue (p );
2481
2482
break ;
2482
2483
case ID_TRUE :
@@ -2496,6 +2497,70 @@ public void copyCurrentEvent(JsonParser p) throws IOException
2496
2497
}
2497
2498
}
2498
2499
2500
+ /**
2501
+ * Same as {@link #copyCurrentEvent} with the exception that copying of numeric
2502
+ * values tries to avoid any conversion losses; in particular for floating-point
2503
+ * numbers. This usually matters when transcoding from textual format like JSON
2504
+ * to a binary format.
2505
+ * See {@link #_copyCurrentFloatValueExact} for details.
2506
+ *
2507
+ * @param p Parser that points to event (token) to copy
2508
+ *
2509
+ * @throws IOException if there is either an underlying I/O problem or encoding
2510
+ * issue at format layer
2511
+ *
2512
+ * @since 2.15
2513
+ */
2514
+ public void copyCurrentEventExact (JsonParser p ) throws IOException
2515
+ {
2516
+ JsonToken t = p .currentToken ();
2517
+ final int token = (t == null ) ? ID_NOT_AVAILABLE : t .id ();
2518
+ switch (token ) {
2519
+ case ID_NOT_AVAILABLE :
2520
+ _reportError ("No current event to copy" );
2521
+ break ; // never gets here
2522
+ case ID_START_OBJECT :
2523
+ writeStartObject ();
2524
+ break ;
2525
+ case ID_END_OBJECT :
2526
+ writeEndObject ();
2527
+ break ;
2528
+ case ID_START_ARRAY :
2529
+ writeStartArray ();
2530
+ break ;
2531
+ case ID_END_ARRAY :
2532
+ writeEndArray ();
2533
+ break ;
2534
+ case ID_FIELD_NAME :
2535
+ writeFieldName (p .getCurrentName ());
2536
+ break ;
2537
+ case ID_STRING :
2538
+ _copyCurrentStringValue (p );
2539
+ break ;
2540
+ case ID_NUMBER_INT :
2541
+ _copyCurrentIntValue (p );
2542
+ break ;
2543
+ case ID_NUMBER_FLOAT :
2544
+ // Different from "copyCurrentEvent"!
2545
+ _copyCurrentFloatValueExact (p );
2546
+ break ;
2547
+ case ID_TRUE :
2548
+ writeBoolean (true );
2549
+ break ;
2550
+ case ID_FALSE :
2551
+ writeBoolean (false );
2552
+ break ;
2553
+ case ID_NULL :
2554
+ writeNull ();
2555
+ break ;
2556
+ case ID_EMBEDDED_OBJECT :
2557
+ writeObject (p .getEmbeddedObject ());
2558
+ break ;
2559
+ default :
2560
+ throw new IllegalStateException ("Internal error: unknown current token, " +t );
2561
+ }
2562
+ }
2563
+
2499
2564
/**
2500
2565
* Method for copying contents of the current event
2501
2566
* <b>and following events that it encloses</b>
@@ -2525,6 +2590,11 @@ public void copyCurrentEvent(JsonParser p) throws IOException
2525
2590
* <b>last event</b> that was copied. This will either be
2526
2591
* the event parser already pointed to (if there were no
2527
2592
* enclosed events), or the last enclosed event copied.
2593
+ *<p>
2594
+ * NOTE: copying of individual tokens/events is handled by delegating
2595
+ * to {@link #copyCurrentEvent} method (make sure to read about difference
2596
+ * between that method and {@link #copyCurrentEventExact} for numeric
2597
+ * value accuracy).
2528
2598
*
2529
2599
* @param p Parser that points to the value to copy
2530
2600
*
@@ -2623,12 +2693,44 @@ protected void _copyCurrentContents(JsonParser p) throws IOException
2623
2693
/**
2624
2694
* Method for copying current {@link JsonToken#VALUE_NUMBER_FLOAT} value;
2625
2695
* overridable by format backend implementations.
2696
+ * Implementation checks
2697
+ * {@link JsonParser#getNumberType()} for declared type and uses matching
2698
+ * accessors: this may cause inexact conversion for some textual formats
2699
+ * (depending on settings). If this is problematic, use
2700
+ * {@lnik #_copyCurrentFloatValueExact} instead (note that doing so may add
2701
+ * overhead).
2626
2702
*
2627
2703
* @param p Parser that points to the value to copy
2628
2704
*
2629
2705
* @since 2.15
2630
2706
*/
2631
2707
protected void _copyCurrentFloatValue (JsonParser p ) throws IOException
2708
+ {
2709
+ NumberType t = p .getNumberType ();
2710
+ if (t == NumberType .BIG_DECIMAL ) {
2711
+ writeNumber (p .getDecimalValue ());
2712
+ } else if (t == NumberType .FLOAT ) {
2713
+ writeNumber (p .getFloatValue ());
2714
+ } else {
2715
+ writeNumber (p .getDoubleValue ());
2716
+ }
2717
+ }
2718
+
2719
+ /**
2720
+ * Method for copying current {@link JsonToken#VALUE_NUMBER_FLOAT} value;
2721
+ * overridable by format backend implementations.
2722
+ * Implementation ensures it uses most accurate accessors necessary to retain
2723
+ * exact value in case of possible numeric conversion: in practice this means
2724
+ * that {@link BigDecimal} is usually used as the representation accessed from
2725
+ * {@link JsonParser}, regardless of whether {@link Double} might be accurate
2726
+ * (since detecting lossy conversion is not possible to do efficiently).
2727
+ * If minimal overhead is desired, use {@link #_copyCurrentFloatValue} instead.
2728
+ *
2729
+ * @param p Parser that points to the value to copy
2730
+ *
2731
+ * @since 2.15
2732
+ */
2733
+ protected void _copyCurrentFloatValueExact (JsonParser p ) throws IOException
2632
2734
{
2633
2735
Number n = p .getNumberValueExact ();
2634
2736
if (n instanceof BigDecimal ) {
0 commit comments