@@ -60,7 +60,21 @@ public enum Feature implements FormatFeature
60
60
*
61
61
* @since 2.20
62
62
*/
63
- READ_UNDEFINED_AS_EMBEDDED_OBJECT (false )
63
+ READ_UNDEFINED_AS_EMBEDDED_OBJECT (false ),
64
+
65
+ /**
66
+ * Feature that determines how a CBOR "simple value" of major type 7 is exposed by parser.
67
+ * <p>
68
+ * When enabled, the parser returns {@link JsonToken#VALUE_EMBEDDED_OBJECT} with
69
+ * an embedded value of type {@link CBORSimpleValue}, allowing the caller to distinguish
70
+ * these values from actual {@link JsonToken#VALUE_NUMBER_INT}s.
71
+ * When disabled, simple values are returned as {@link JsonToken#VALUE_NUMBER_INT}.
72
+ *<p>
73
+ * The default value is {@code false} for backwards compatibility (with versions prior to 2.20).
74
+ *
75
+ * @since 2.20
76
+ */
77
+ READ_SIMPLE_VALUE_AS_EMBEDDED_OBJECT (false )
64
78
;
65
79
66
80
private final boolean _defaultState ;
@@ -363,6 +377,14 @@ public int getFirstTag() {
363
377
*/
364
378
protected TagList _tagValues = new TagList ();
365
379
380
+ /**
381
+ * When major type 7 value is encountered and exposed as {@link JsonToken#VALUE_EMBEDDED_OBJECT},
382
+ * the value will be stored here.
383
+ *
384
+ * @since 2.20
385
+ */
386
+ protected CBORSimpleValue _simpleValue ;
387
+
366
388
/**
367
389
* Flag that indicates that the current token has not yet
368
390
* been fully processed, and needs to be finished for
@@ -824,9 +846,9 @@ public JsonToken nextToken() throws IOException
824
846
_skipIncomplete ();
825
847
}
826
848
_tokenInputTotal = _currInputProcessed + _inputPtr ;
827
- // also: clear any data retained so far
828
- _numTypesValid = NR_UNKNOWN ;
829
- _binaryValue = null ;
849
+
850
+ // also: clear any data retained for previous token
851
+ clearRetainedValues () ;
830
852
831
853
// First: need to keep track of lengths of defined-length Arrays and
832
854
// Objects (to materialize END_ARRAY/END_OBJECT as necessary);
@@ -1453,12 +1475,12 @@ public boolean nextFieldName(SerializableString str) throws IOException
1453
1475
{
1454
1476
// Two parsing modes; can only succeed if expecting field name, so handle that first:
1455
1477
if (_streamReadContext .inObject () && _currToken != JsonToken .FIELD_NAME ) {
1456
- _numTypesValid = NR_UNKNOWN ;
1457
1478
if (_tokenIncomplete ) {
1458
1479
_skipIncomplete ();
1459
1480
}
1460
1481
_tokenInputTotal = _currInputProcessed + _inputPtr ;
1461
- _binaryValue = null ;
1482
+ // need to clear retained values for previous token
1483
+ clearRetainedValues ();
1462
1484
_tagValues .clear ();
1463
1485
// completed the whole Object?
1464
1486
if (!_streamReadContext .expectMoreValues ()) {
@@ -1506,19 +1528,19 @@ public boolean nextFieldName(SerializableString str) throws IOException
1506
1528
}
1507
1529
}
1508
1530
// otherwise just fall back to default handling; should occur rarely
1509
- return (nextToken () == JsonToken .FIELD_NAME ) && str .getValue ().equals (getCurrentName ());
1531
+ return (nextToken () == JsonToken .FIELD_NAME ) && str .getValue ().equals (currentName ());
1510
1532
}
1511
1533
1512
1534
@ Override
1513
1535
public String nextFieldName () throws IOException
1514
1536
{
1515
1537
if (_streamReadContext .inObject () && _currToken != JsonToken .FIELD_NAME ) {
1516
- _numTypesValid = NR_UNKNOWN ;
1517
1538
if (_tokenIncomplete ) {
1518
1539
_skipIncomplete ();
1519
1540
}
1520
1541
_tokenInputTotal = _currInputProcessed + _inputPtr ;
1521
- _binaryValue = null ;
1542
+ // need to clear retained values for previous token
1543
+ clearRetainedValues ();
1522
1544
_tagValues .clear ();
1523
1545
// completed the whole Object?
1524
1546
if (!_streamReadContext .expectMoreValues ()) {
@@ -1843,7 +1865,10 @@ public Object getEmbeddedObject() throws IOException
1843
1865
if (_tokenIncomplete ) {
1844
1866
_finishToken ();
1845
1867
}
1846
- if (_currToken == JsonToken .VALUE_EMBEDDED_OBJECT ) {
1868
+ if (_currToken == JsonToken .VALUE_EMBEDDED_OBJECT ) {
1869
+ if (_simpleValue != null ) {
1870
+ return _simpleValue ;
1871
+ }
1847
1872
return _binaryValue ;
1848
1873
}
1849
1874
return null ;
@@ -1933,11 +1958,11 @@ private final byte[] _getBinaryFromString(Base64Variant variant) throws IOExcept
1933
1958
/**
1934
1959
* Checking whether the current token represents an `undefined` value (0xF7).
1935
1960
* <p>
1936
- * This method allows distinguishing between real {@code null} and ` undefined` ,
1961
+ * This method allows distinguishing between real {@code null} and {@code undefined} ,
1937
1962
* even if {@link CBORParser.Feature#READ_UNDEFINED_AS_EMBEDDED_OBJECT} is disabled
1938
1963
* and the token is reported as {@link JsonToken#VALUE_NULL}.
1939
1964
*
1940
- * @return {@code true} if current token is an ` undefined` , {@code false} otherwise
1965
+ * @return {@code true} if current token is an {@code undefined} , {@code false} otherwise
1941
1966
*
1942
1967
* @since 2.20
1943
1968
*/
@@ -3713,38 +3738,50 @@ protected JsonToken _decodeUndefinedValue() {
3713
3738
* Helper method that deals with details of decoding unallocated "simple values"
3714
3739
* and exposing them as expected token.
3715
3740
* <p>
3716
- * As of Jackson 2.12, simple values are exposed as
3717
- * {@link JsonToken#VALUE_NUMBER_INT}s,
3718
- * but in later versions this is planned to be changed to separate value type.
3741
+ * Starting with Jackson 2.20, this behavior can be changed by enabling the
3742
+ * {@link CBORParser.Feature#READ_SIMPLE_VALUE_AS_EMBEDDED_OBJECT}
3743
+ * feature, in which case simple values are returned as {@link JsonToken#VALUE_EMBEDDED_OBJECT} with an
3744
+ * embedded {@link CBORSimpleValue} instance.
3719
3745
*
3720
3746
* @since 2.12
3721
3747
*/
3722
3748
public JsonToken _decodeSimpleValue (int lowBits , int ch ) throws IOException {
3723
3749
if (lowBits > 24 ) {
3724
3750
_invalidToken (ch );
3725
3751
}
3752
+ final boolean simpleAsEmbedded = Feature .READ_SIMPLE_VALUE_AS_EMBEDDED_OBJECT .enabledIn (_formatFeatures );
3726
3753
if (lowBits < 24 ) {
3727
- _numberInt = lowBits ;
3754
+ if (simpleAsEmbedded ) {
3755
+ _simpleValue = new CBORSimpleValue (lowBits );
3756
+ } else {
3757
+ _numberInt = lowBits ;
3758
+ }
3728
3759
} else { // need another byte
3729
3760
if (_inputPtr >= _inputEnd ) {
3730
3761
loadMoreGuaranteed ();
3731
3762
}
3732
- _numberInt = _inputBuffer [ _inputPtr ++] & 0xFF ;
3763
+
3733
3764
// As per CBOR spec, values below 32 not allowed to avoid
3734
3765
// confusion (as well as guarantee uniqueness of encoding)
3735
- if (_numberInt < 32 ) {
3766
+ int value = _inputBuffer [_inputPtr ++] & 0xFF ;
3767
+ if (value < 32 ) {
3736
3768
throw _constructError ("Invalid second byte for simple value: 0x"
3737
- +Integer .toHexString (_numberInt )+" (only values 0x20 - 0xFF allowed)" );
3769
+ +Integer .toHexString (value )+" (only values 0x20 - 0xFF allowed)" );
3770
+ }
3771
+
3772
+ if (simpleAsEmbedded ) {
3773
+ _simpleValue = new CBORSimpleValue (value );
3774
+ } else {
3775
+ _numberInt = value ;
3738
3776
}
3739
3777
}
3740
3778
3741
- // 25-Nov-2020, tatu: Although ideally we should report these
3742
- // as `JsonToken.VALUE_EMBEDDED_OBJECT`, due to late addition
3743
- // of handling in 2.12, simple value in 2.12 will be reported
3744
- // as simple ints.
3779
+ if (simpleAsEmbedded ) {
3780
+ return JsonToken .VALUE_EMBEDDED_OBJECT ;
3781
+ }
3745
3782
3746
3783
_numTypesValid = NR_INT ;
3747
- return ( JsonToken .VALUE_NUMBER_INT ) ;
3784
+ return JsonToken .VALUE_NUMBER_INT ;
3748
3785
}
3749
3786
3750
3787
/*
@@ -4101,4 +4138,11 @@ private void createChildObjectContext(final int len) throws IOException {
4101
4138
_streamReadContext = _streamReadContext .createChildObjectContext (len );
4102
4139
_streamReadConstraints .validateNestingDepth (_streamReadContext .getNestingDepth ());
4103
4140
}
4141
+
4142
+ // @since 2.20
4143
+ private void clearRetainedValues () {
4144
+ _numTypesValid = NR_UNKNOWN ;
4145
+ _binaryValue = null ;
4146
+ _simpleValue = null ;
4147
+ }
4104
4148
}
0 commit comments