Skip to content

Commit 2bdb102

Browse files
committed
Merge branch '2.19' into 2.20
2 parents 92e2846 + 8e10994 commit 2bdb102

3 files changed

Lines changed: 183 additions & 0 deletions

File tree

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package com.fasterxml.jackson.dataformat.cbor.gen.constraints;
2+
3+
import java.io.ByteArrayInputStream;
4+
import java.io.ByteArrayOutputStream;
5+
6+
import org.junit.jupiter.api.Test;
7+
8+
import com.fasterxml.jackson.core.JsonGenerator;
9+
import com.fasterxml.jackson.core.JsonParser;
10+
import com.fasterxml.jackson.core.StreamReadConstraints;
11+
import com.fasterxml.jackson.core.exc.StreamConstraintsException;
12+
13+
import com.fasterxml.jackson.dataformat.cbor.CBORFactory;
14+
import com.fasterxml.jackson.dataformat.cbor.CBORTestBase;
15+
import com.fasterxml.jackson.dataformat.cbor.databind.CBORMapper;
16+
17+
import static org.junit.jupiter.api.Assertions.assertEquals;
18+
import static org.junit.jupiter.api.Assertions.fail;
19+
20+
// [dataformats-binary#651] Validate maxTokenCount support for CBOR
21+
public class TokenCountCBORReadTest extends CBORTestBase
22+
{
23+
private final CBORMapper MAPPER = cborMapper();
24+
25+
// Verify token count is tracked accurately
26+
@Test
27+
public void testTokenCountIsTracked() throws Exception
28+
{
29+
// [1, 2, 3]: START_ARRAY, VALUE_NUMBER_INT x3, END_ARRAY = 5 tokens
30+
byte[] doc = createDoc(3);
31+
CBORMapper mapper = mapperWithMaxTokenCount(Long.MAX_VALUE);
32+
try (JsonParser p = mapper.createParser(doc)) {
33+
assertEquals(0L, p.currentTokenCount());
34+
while (p.nextToken() != null) { }
35+
assertEquals(5L, p.currentTokenCount());
36+
}
37+
}
38+
39+
@Test
40+
public void testTokenCountLimitWithStream() throws Exception
41+
{
42+
// createDoc(100) produces START_ARRAY + 100xVALUE_NUMBER_INT + END_ARRAY = 102 tokens
43+
byte[] doc = createDoc(100);
44+
CBORMapper mapper = mapperWithMaxTokenCount(10);
45+
try (JsonParser p = mapper.createParser(new ByteArrayInputStream(doc))) {
46+
while (p.nextToken() != null) { }
47+
fail("expected StreamConstraintsException");
48+
} catch (StreamConstraintsException e) {
49+
verifyException(e, "Token count");
50+
verifyException(e, "exceeds the maximum allowed (10,");
51+
}
52+
}
53+
54+
@Test
55+
public void testTokenCountLimitWithByteArray() throws Exception
56+
{
57+
// createDoc(100) produces START_ARRAY + 100xVALUE_NUMBER_INT + END_ARRAY = 102 tokens
58+
byte[] doc = createDoc(100);
59+
CBORMapper mapper = mapperWithMaxTokenCount(10);
60+
try (JsonParser p = mapper.createParser(doc)) {
61+
while (p.nextToken() != null) { }
62+
fail("expected StreamConstraintsException");
63+
} catch (StreamConstraintsException e) {
64+
verifyException(e, "Token count");
65+
verifyException(e, "exceeds the maximum allowed (10,");
66+
}
67+
}
68+
69+
private CBORMapper mapperWithMaxTokenCount(long maxTokenCount) {
70+
return cborMapper(
71+
CBORFactory.builder()
72+
.streamReadConstraints(StreamReadConstraints.builder()
73+
.maxTokenCount(maxTokenCount).build())
74+
.build());
75+
}
76+
77+
// Creates a CBOR-encoded array document with the given number of integer elements.
78+
// Token count = numValues + 2 (START_ARRAY + END_ARRAY)
79+
private byte[] createDoc(int numValues) throws Exception {
80+
ByteArrayOutputStream out = new ByteArrayOutputStream();
81+
try (JsonGenerator g = MAPPER.createGenerator(out)) {
82+
g.writeStartArray();
83+
for (int i = 0; i < numValues; i++) {
84+
g.writeNumber(i);
85+
}
86+
g.writeEndArray();
87+
}
88+
return out.toByteArray();
89+
}
90+
}

release-notes/VERSION-2.x

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ No changes since 2.19.1
104104
use of Avro core 1.12.1 (2.x)
105105
#649: (cbor, smile) `StreamReadConstraints.maxDocumentLength` not checked
106106
when creating parser with fixed buffer
107+
#651: (smile) Ensure Smile backend supports `StreamReadConstraints.maxTokenCount`
108+
#652: (cbor) Ensure CBOR backend supports `StreamReadConstraints.maxTokenCount`
107109

108110
2.18.5 (27-Oct-2025)
109111

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package com.fasterxml.jackson.dataformat.smile.constraints;
2+
3+
import java.io.ByteArrayInputStream;
4+
import java.io.ByteArrayOutputStream;
5+
6+
import org.junit.jupiter.api.Test;
7+
8+
import com.fasterxml.jackson.core.JsonGenerator;
9+
import com.fasterxml.jackson.core.JsonParser;
10+
import com.fasterxml.jackson.core.StreamReadConstraints;
11+
import com.fasterxml.jackson.core.exc.StreamConstraintsException;
12+
13+
import com.fasterxml.jackson.dataformat.smile.BaseTestForSmile;
14+
import com.fasterxml.jackson.dataformat.smile.SmileFactory;
15+
import com.fasterxml.jackson.dataformat.smile.databind.SmileMapper;
16+
17+
import static org.junit.jupiter.api.Assertions.assertEquals;
18+
import static org.junit.jupiter.api.Assertions.fail;
19+
20+
// [dataformats-binary#651] Validate maxTokenCount support for Smile
21+
public class TokenCountSmileReadTest extends BaseTestForSmile
22+
{
23+
private final SmileMapper MAPPER = new SmileMapper();
24+
25+
// Verify token count is tracked accurately
26+
@Test
27+
public void testTokenCountIsTracked() throws Exception
28+
{
29+
// [1, 2, 3]: START_ARRAY, VALUE_NUMBER_INT x3, END_ARRAY = 5 tokens
30+
byte[] doc = createDoc(3);
31+
SmileMapper mapper = mapperWithMaxTokenCount(Long.MAX_VALUE);
32+
try (JsonParser p = mapper.createParser(doc)) {
33+
assertEquals(0L, p.currentTokenCount());
34+
while (p.nextToken() != null) { }
35+
assertEquals(5L, p.currentTokenCount());
36+
}
37+
}
38+
39+
@Test
40+
public void testTokenCountLimitWithStream() throws Exception
41+
{
42+
// createDoc(100) produces START_ARRAY + 100xVALUE_NUMBER_INT + END_ARRAY = 102 tokens
43+
byte[] doc = createDoc(100);
44+
SmileMapper mapper = mapperWithMaxTokenCount(10);
45+
try (JsonParser p = mapper.createParser(new ByteArrayInputStream(doc))) {
46+
while (p.nextToken() != null) { }
47+
fail("expected StreamConstraintsException");
48+
} catch (StreamConstraintsException e) {
49+
verifyException(e, "Token count");
50+
verifyException(e, "exceeds the maximum allowed (10,");
51+
}
52+
}
53+
54+
@Test
55+
public void testTokenCountLimitWithByteArray() throws Exception
56+
{
57+
// createDoc(100) produces START_ARRAY + 100xVALUE_NUMBER_INT + END_ARRAY = 102 tokens
58+
byte[] doc = createDoc(100);
59+
SmileMapper mapper = mapperWithMaxTokenCount(10);
60+
try (JsonParser p = mapper.createParser(doc)) {
61+
while (p.nextToken() != null) { }
62+
fail("expected StreamConstraintsException");
63+
} catch (StreamConstraintsException e) {
64+
verifyException(e, "Token count");
65+
verifyException(e, "exceeds the maximum allowed (10,");
66+
}
67+
}
68+
69+
private SmileMapper mapperWithMaxTokenCount(long maxTokenCount) {
70+
return SmileMapper.builder(
71+
SmileFactory.builder()
72+
.streamReadConstraints(StreamReadConstraints.builder()
73+
.maxTokenCount(maxTokenCount).build())
74+
.build())
75+
.build();
76+
}
77+
78+
// Creates a Smile-encoded array document with the given number of integer elements.
79+
// Token count = numValues + 2 (START_ARRAY + END_ARRAY)
80+
private byte[] createDoc(int numValues) throws Exception {
81+
ByteArrayOutputStream out = new ByteArrayOutputStream();
82+
try (JsonGenerator g = MAPPER.createGenerator(out)) {
83+
g.writeStartArray();
84+
for (int i = 0; i < numValues; i++) {
85+
g.writeNumber(i);
86+
}
87+
g.writeEndArray();
88+
}
89+
return out.toByteArray();
90+
}
91+
}

0 commit comments

Comments
 (0)