Skip to content

Commit 3606363

Browse files
authored
More testing wrt core#1434 (verifying 2.x behavior), fixes (#597)
1 parent 01aa0bc commit 3606363

File tree

9 files changed

+86
-5
lines changed

9 files changed

+86
-5
lines changed

avro/src/test/java/com/fasterxml/jackson/dataformat/avro/AvroNumberTest.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import com.fasterxml.jackson.core.JsonParser;
1010
import com.fasterxml.jackson.core.JsonParser.NumberType;
1111
import com.fasterxml.jackson.core.JsonParser.NumberTypeFP;
12+
import com.fasterxml.jackson.core.exc.StreamReadException;
1213
import com.fasterxml.jackson.core.JsonToken;
1314
import com.fasterxml.jackson.core.io.SerializedString;
1415
import com.fasterxml.jackson.dataformat.avro.testsupport.LimitingInputStream;
@@ -69,8 +70,12 @@ public void testNumberCoercions() throws Exception
6970
byte[] bytes = MAPPER.writer(schema).writeValueAsBytes(input);
7071
JsonParser p = MAPPER.getFactory()
7172
.createParser(LimitingInputStream.wrap(bytes, 42));
73+
7274
p.setSchema(schema);
75+
76+
_verifyGetNumberTypeFail(p, "null");
7377
assertToken(JsonToken.START_OBJECT, p.nextToken());
78+
_verifyGetNumberTypeFail(p, "START_OBJECT");
7479

7580
assertTrue(p.nextFieldName(new SerializedString("i")));
7681
assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
@@ -122,6 +127,19 @@ public void testNumberCoercions() throws Exception
122127
assertEquals(Double.valueOf(input.d), p.getNumberValue());
123128

124129
assertToken(JsonToken.END_OBJECT, p.nextToken());
130+
_verifyGetNumberTypeFail(p, "END_OBJECT");
125131
p.close();
132+
133+
_verifyGetNumberTypeFail(p, "null");
134+
}
135+
136+
private void _verifyGetNumberTypeFail(JsonParser p, String token) throws Exception
137+
{
138+
try {
139+
p.getNumberType();
140+
fail("Should not pass");
141+
} catch (StreamReadException e) {
142+
verifyException(e, "Current token ("+token+") not numeric, can not use numeric");
143+
}
126144
}
127145
}

cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORParser.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -769,6 +769,10 @@ public void close() throws IOException {
769769
if (!_closed) {
770770
_closed = true;
771771
_symbols.release();
772+
// 30-May-2025, tatu: was missing before 2.20
773+
if (JsonParser.Feature.CLEAR_CURRENT_TOKEN_ON_CLOSE.enabledIn(_features)) {
774+
_currToken = null;
775+
}
772776
try {
773777
_closeInput();
774778
} finally {

cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/parse/CBORNumberParsingGetType1433Test.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,6 @@ void getNumberType() throws Exception
5151
_verifyGetNumberTypeFail(p, "VALUE_TRUE");
5252
assertToken(JsonToken.END_ARRAY, p.nextToken());
5353
_verifyGetNumberTypeFail(p, "END_ARRAY");
54-
assertNull(p.nextToken());
55-
_verifyGetNumberTypeFail(p, "null");
5654
p.close();
5755
_verifyGetNumberTypeFail(p, "null");
5856
}

ion/src/main/java/com/fasterxml/jackson/dataformat/ion/IonParser.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,10 @@ public boolean isClosed() {
254254
@Override
255255
public void close() throws IOException {
256256
if (!_closed) {
257+
// 30-May-2025, tatu: was missing before 2.20
258+
if (JsonParser.Feature.CLEAR_CURRENT_TOKEN_ON_CLOSE.enabledIn(_features)) {
259+
_currToken = null;
260+
}
257261
// should only close if manage the resource
258262
if (_ioContext.isResourceManaged()) {
259263
Object src = _ioContext.contentReference().getRawContent();
@@ -448,6 +452,10 @@ private void _verifyIsNumberToken() throws IOException
448452
}
449453
}
450454

455+
// NOTE: Ion implementation follows original (up to 2.19) JsonParser Javadocs
456+
// behavior (if non-number, return `null`), which is different from other
457+
// backends (if non-number, throw exception). But since 3.0 will switch to
458+
// "return null for non-numbers", Ion behavior is retained in 2.20+.
451459
@Override
452460
public NumberType getNumberType() throws IOException
453461
{

ion/src/test/java/com/fasterxml/jackson/dataformat/ion/IonParserTest.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import com.amazon.ion.*;
2222
import com.amazon.ion.system.IonSystemBuilder;
23+
2324
import org.junit.jupiter.api.Test;
2425

2526
import com.fasterxml.jackson.core.*;
@@ -36,6 +37,10 @@ public void testGetNumberTypeAndValue() throws Exception {
3637
Integer intValue = Integer.MAX_VALUE;
3738
IonValue ionInt = ion.newInt(intValue);
3839
IonParser intParser = new IonFactory().createParser(ionInt);
40+
41+
// initially no current token so:
42+
_verifyGetNumberTypeFail(intParser, "null");
43+
3944
assertEquals(JsonToken.VALUE_NUMBER_INT, intParser.nextToken());
4045
assertEquals(JsonParser.NumberType.INT, intParser.getNumberType());
4146
assertEquals(JsonParser.NumberTypeFP.UNKNOWN, intParser.getNumberTypeFP());
@@ -44,14 +49,17 @@ public void testGetNumberTypeAndValue() throws Exception {
4449
Long longValue = Long.MAX_VALUE;
4550
IonValue ionLong = ion.newInt(longValue);
4651
IonParser longParser = new IonFactory().createParser(ionLong);
52+
_verifyGetNumberTypeFail(longParser, "null");
4753
assertEquals(JsonToken.VALUE_NUMBER_INT, longParser.nextToken());
4854
assertEquals(JsonParser.NumberType.LONG, longParser.getNumberType());
4955
assertEquals(JsonParser.NumberTypeFP.UNKNOWN, intParser.getNumberTypeFP());
5056
assertEquals(longValue, longParser.getNumberValue());
57+
assertNull(longParser.nextToken());
5158

5259
BigInteger bigIntValue = new BigInteger(Long.MAX_VALUE + "1");
5360
IonValue ionBigInt = ion.newInt(bigIntValue);
5461
IonParser bigIntParser = new IonFactory().createParser(ionBigInt);
62+
_verifyGetNumberTypeFail(bigIntParser, "null");
5563
assertEquals(JsonToken.VALUE_NUMBER_INT, bigIntParser.nextToken());
5664
assertEquals(JsonParser.NumberType.BIG_INTEGER, bigIntParser.getNumberType());
5765
assertEquals(JsonParser.NumberTypeFP.UNKNOWN, intParser.getNumberTypeFP());
@@ -60,6 +68,7 @@ public void testGetNumberTypeAndValue() throws Exception {
6068
Double decimalValue = Double.MAX_VALUE;
6169
IonValue ionDecimal = ion.newDecimal(decimalValue);
6270
IonParser decimalParser = new IonFactory().createParser(ionDecimal);
71+
_verifyGetNumberTypeFail(decimalParser, "null");
6372
assertEquals(JsonToken.VALUE_NUMBER_FLOAT, decimalParser.nextToken());
6473
assertEquals(JsonParser.NumberType.BIG_DECIMAL, decimalParser.getNumberType());
6574
assertEquals(JsonParser.NumberTypeFP.BIG_DECIMAL, decimalParser.getNumberTypeFP());
@@ -68,6 +77,7 @@ public void testGetNumberTypeAndValue() throws Exception {
6877
Double floatValue = Double.MAX_VALUE;
6978
IonValue ionFloat = ion.newFloat(floatValue);
7079
IonParser floatParser = new IonFactory().createParser(ionFloat);
80+
_verifyGetNumberTypeFail(floatParser, "null");
7181
assertEquals(JsonToken.VALUE_NUMBER_FLOAT, floatParser.nextToken());
7282
assertEquals(JsonParser.NumberType.DOUBLE, floatParser.getNumberType());
7383
// [dataformats-binary#490]: float coerces to double
@@ -77,6 +87,7 @@ public void testGetNumberTypeAndValue() throws Exception {
7787
BigDecimal bigDecimalValue = new BigDecimal(Double.MAX_VALUE + "1");
7888
IonValue ionBigDecimal = ion.newDecimal(bigDecimalValue);
7989
IonParser bigDecimalParser = new IonFactory().createParser(ionBigDecimal);
90+
_verifyGetNumberTypeFail(bigDecimalParser, "null");
8091
assertEquals(JsonToken.VALUE_NUMBER_FLOAT, bigDecimalParser.nextToken());
8192
assertEquals(JsonParser.NumberType.BIG_DECIMAL, bigDecimalParser.getNumberType());
8293
assertEquals(JsonParser.NumberTypeFP.BIG_DECIMAL, bigDecimalParser.getNumberTypeFP());
@@ -139,9 +150,11 @@ public void testIonExceptionIsWrapped() throws IOException {
139150
IonFactory f = new IonFactory();
140151
try (IonParser parser = (IonParser) f.createParser("[ 12, true ) ]")) {
141152
assertEquals(JsonToken.START_ARRAY, parser.nextToken());
153+
_verifyGetNumberTypeFail(parser, "START_ARRAY");
142154
assertEquals(JsonToken.VALUE_NUMBER_INT, parser.nextValue());
143155
assertEquals(12, parser.getIntValue());
144156
assertEquals(JsonToken.VALUE_TRUE, parser.nextValue());
157+
_verifyGetNumberTypeFail(parser, "VALUE_TRUE");
145158
parser.nextValue();
146159
}
147160
});
@@ -193,4 +206,16 @@ public void testUnknownSymbolExceptionForAnnotationIsWrapped() throws IOExceptio
193206
}
194207
});
195208
}
209+
210+
// 30-May-2025, tatu: NOTE: IonParser implements `JsonParser.getNumberType()` way
211+
// documented before 2.19 ("null for non-numeric types") unlike all other backends
212+
// (which throws StreamReadException). In 2.19.1 Javadocs were updated to reflect
213+
// actual behavior, so in theory IonParser is non-compliant. However, for compatibility
214+
// reasons we'll let that be.
215+
// Further, as per [jackson-core#1434], Jackson 3.0 will actually change definition
216+
// to NOT throw an exception but return null -- what Ion already does.
217+
private void _verifyGetNumberTypeFail(JsonParser p, String token) throws Exception
218+
{
219+
assertNull(p.getNumberType());
220+
}
196221
}

protobuf/src/main/java/com/fasterxml/jackson/dataformat/protobuf/ProtobufParser.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,10 @@ public void close() throws IOException
448448
_state = STATE_CLOSED;
449449
if (!_closed) {
450450
_closed = true;
451+
// 30-May-2025, tatu: was missing before 2.20
452+
if (JsonParser.Feature.CLEAR_CURRENT_TOKEN_ON_CLOSE.enabledIn(_features)) {
453+
_currToken = null;
454+
}
451455
try {
452456
_closeInput();
453457
} finally {
@@ -461,6 +465,12 @@ public void close() throws IOException
461465
_parsingContext = _parsingContext.getParent();
462466
}
463467
_parsingContext.setCurrentName(null);
468+
} else {
469+
// 31-May-2025, tatu: To work around [dataformats-binary#598],
470+
// need to forcibly clear current token even in this case
471+
if (JsonParser.Feature.CLEAR_CURRENT_TOKEN_ON_CLOSE.enabledIn(_features)) {
472+
_currToken = null;
473+
}
464474
}
465475
}
466476

protobuf/src/test/java/com/fasterxml/jackson/dataformat/protobuf/ReadSimpleTest.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import com.fasterxml.jackson.core.*;
99
import com.fasterxml.jackson.core.JsonParser.NumberType;
1010
import com.fasterxml.jackson.core.JsonParser.NumberTypeFP;
11+
import com.fasterxml.jackson.core.exc.StreamReadException;
1112
import com.fasterxml.jackson.databind.*;
1213
import com.fasterxml.jackson.dataformat.protobuf.schema.ProtobufSchema;
1314
import com.fasterxml.jackson.dataformat.protobuf.schema.ProtobufSchemaLoader;
@@ -91,10 +92,13 @@ public void testReadPointIntStreaming() throws Exception
9192
assertEquals(6, bytes.length);
9293

9394
// actually let's also try via streaming parser
94-
JsonParser p = MAPPER.getFactory().createParser(bytes);
95+
JsonParser p = MAPPER.createParser(bytes);
9596
p.setSchema(schema);
97+
98+
_verifyGetNumberTypeFail(p, "null");
9699
assertToken(JsonToken.START_OBJECT, p.nextToken());
97100
assertNull(p.currentName());
101+
_verifyGetNumberTypeFail(p, "START_OBJECT");
98102
assertToken(JsonToken.FIELD_NAME, p.nextToken());
99103
assertEquals("x", p.currentName());
100104
assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
@@ -109,8 +113,10 @@ public void testReadPointIntStreaming() throws Exception
109113
assertEquals(input.y, p.getIntValue());
110114
assertToken(JsonToken.END_OBJECT, p.nextToken());
111115
assertNull(p.currentName());
116+
_verifyGetNumberTypeFail(p, "END_OBJECT");
112117
p.close();
113118
assertNull(p.currentName());
119+
_verifyGetNumberTypeFail(p, "null");
114120
}
115121

116122
@Test
@@ -469,4 +475,14 @@ public void testStringArraySimpleLowLimit() throws Exception
469475
"unexpected message: " + message);
470476
}
471477
}
478+
479+
private void _verifyGetNumberTypeFail(JsonParser p, String token) throws Exception
480+
{
481+
try {
482+
p.getNumberType();
483+
fail("Should not pass");
484+
} catch (StreamReadException e) {
485+
verifyException(e, "Current token ("+token+") not numeric, can not use numeric");
486+
}
487+
}
472488
}

smile/src/main/java/com/fasterxml/jackson/dataformat/smile/SmileParserBase.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,10 @@ public final void close() throws IOException {
397397
_closed = true;
398398
_inputEnd = 0;
399399
_symbols.release();
400+
// 30-May-2025, tatu: was missing before 2.20
401+
if (JsonParser.Feature.CLEAR_CURRENT_TOKEN_ON_CLOSE.enabledIn(_features)) {
402+
_currToken = null;
403+
}
400404
try {
401405
_closeInput();
402406
} finally {

smile/src/test/java/com/fasterxml/jackson/dataformat/smile/parse/SmileNumberParsingGetType1433Test.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,6 @@ void getNumberType() throws Exception
5151
_verifyGetNumberTypeFail(p, "VALUE_TRUE");
5252
assertToken(JsonToken.END_ARRAY, p.nextToken());
5353
_verifyGetNumberTypeFail(p, "END_ARRAY");
54-
assertNull(p.nextToken());
55-
_verifyGetNumberTypeFail(p, "null");
5654
p.close();
5755
_verifyGetNumberTypeFail(p, "null");
5856
}

0 commit comments

Comments
 (0)