Skip to content

Commit 2d22f52

Browse files
authored
Add tests for #1491, fix (#1492)
1 parent bac78c0 commit 2d22f52

File tree

4 files changed

+165
-6
lines changed

4 files changed

+165
-6
lines changed

release-notes/VERSION

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@ JSON library.
1515
=== Releases ===
1616
------------------------------------------------------------------------
1717

18+
3.1.0 (not yet released)
19+
20+
-
21+
22+
3.0.2 (not yet released)
23+
24+
#1491: Mismatched property name for byte-backed `JsonParser.nextNameMatch(PropertyNameMatcher)`
25+
(fix by @cowtowncoder, w/ Claude code)
26+
1827
3.0.1 (21-Oct-2025)
1928

2029
No changes since 3.0.0

src/main/java/tools/jackson/core/json/UTF8StreamJsonParser.java

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1573,6 +1573,8 @@ protected final int _matchLongName(PropertyNameMatcher matcher, int qptr,
15731573
if (i != INT_QUOTE) {
15741574
return -1;
15751575
}
1576+
// [core#1491]: Need to include partial quad in matching
1577+
_quadBuffer[qlen++] = q;
15761578
_quadPtr = qptr;
15771579
return matcher.matchByQuad(_quadBuffer, qlen);
15781580
}
@@ -1582,26 +1584,32 @@ protected final int _matchLongName(PropertyNameMatcher matcher, int qptr,
15821584
if (i != INT_QUOTE) {
15831585
return -1;
15841586
}
1585-
// q = _padLastQuadNoCheck(q, (-1 << 8));
1586-
break;
1587+
// [core#1491]: Need to include partial quad in matching
1588+
_quadBuffer[qlen++] = q;
1589+
_quadPtr = qptr;
1590+
return matcher.matchByQuad(_quadBuffer, qlen);
15871591
}
15881592
q = (q << 8) | i;
15891593
i = input[qptr++] & 0xFF;
15901594
if (codes[i] != 0) {
15911595
if (i != INT_QUOTE) {
15921596
return -1;
15931597
}
1594-
// q = _padLastQuadNoCheck(q, (-1 << 16));
1595-
break;
1598+
// [core#1491]: Need to include partial quad in matching
1599+
_quadBuffer[qlen++] = q;
1600+
_quadPtr = qptr;
1601+
return matcher.matchByQuad(_quadBuffer, qlen);
15961602
}
15971603
q = (q << 8) | i;
15981604
i = input[qptr++] & 0xFF;
15991605
if (codes[i] != 0) {
16001606
if (i != INT_QUOTE) {
16011607
return -1;
16021608
}
1603-
// q = _padLastQuadNoCheck(q, (-1 << 24));
1604-
break;
1609+
// [core#1491]: Need to include partial quad in matching
1610+
_quadBuffer[qlen++] = q;
1611+
_quadPtr = qptr;
1612+
return matcher.matchByQuad(_quadBuffer, qlen);
16051613
}
16061614
// Nope, no end in sight. Need to grow quad array etc
16071615
if (qlen >= _quadBuffer.length) {

src/test/java/tools/jackson/core/unittest/sym/BinaryNameMatcherTest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ public void testSmallMatching()
1919
// First small (1 - 4)
2020
_testMatching("single");
2121
_testMatching("1", "2a");
22+
//[core#1491]
23+
_testMatching("aaaabbbbcccc", "aaaabbbbcccc2");
2224
_testMatching("first", "secondlong", "3rd");
2325
}
2426

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
package tools.jackson.core.unittest.sym;
2+
3+
import java.util.List;
4+
5+
import org.junit.jupiter.api.Test;
6+
7+
import tools.jackson.core.*;
8+
import tools.jackson.core.io.SerializedString;
9+
import tools.jackson.core.json.JsonFactory;
10+
import tools.jackson.core.sym.PropertyNameMatcher;
11+
import tools.jackson.core.util.Named;
12+
13+
import static org.junit.jupiter.api.Assertions.assertEquals;
14+
import static org.junit.jupiter.api.Assertions.assertFalse;
15+
import static org.junit.jupiter.api.Assertions.assertTrue;
16+
17+
// [core#1491]: PropertyNameMatcher collision
18+
public class PropertyNameMatcher1491Test
19+
extends tools.jackson.core.unittest.JacksonCoreTestBase
20+
{
21+
// Occurs with min of 12 chars (multiples of 4, 16 works).
22+
// Choice of first N does not matter, nor last (13th);
23+
// All of below show failure
24+
25+
private final static String KEY_1 = "aaaabbbbcccc";
26+
private final static String KEY_2 = "aaaabbbbcccc2";
27+
// private final String KEY_1 = "a234b234c234";
28+
// private final String KEY_2 = "a234b234c234x";
29+
// private final String KEY_1 = "a234b234c234dXYZ";
30+
// private final String KEY_2 = "a234b234c234dXYZ0";
31+
32+
33+
private final static Named NAMED_1 = Named.fromString(KEY_1);
34+
private final static Named NAMED_2 = Named.fromString(KEY_2);
35+
36+
private final static String DOC_1491 = """
37+
{
38+
"%s": "v3",
39+
"%s": "v4"
40+
}
41+
""".formatted(KEY_1, KEY_2);
42+
43+
@Test
44+
void test1491ViaRegularParserBytes() throws Exception {
45+
_testViaRegularParser(MODE_INPUT_STREAM);
46+
_testViaRegularParser(MODE_INPUT_STREAM_THROTTLED);
47+
}
48+
49+
@Test
50+
void test1491ViaRegularParserChars() throws Exception {
51+
_testViaRegularParser(MODE_READER);
52+
}
53+
54+
private void _testViaRegularParser(int mode) throws Exception
55+
{
56+
// First, regular reads
57+
try (JsonParser p = createParser(mode, DOC_1491)) {
58+
assertToken(JsonToken.START_OBJECT, p.nextToken());
59+
assertToken(JsonToken.PROPERTY_NAME, p.nextToken());
60+
assertEquals(KEY_1, p.currentName());
61+
assertToken(JsonToken.VALUE_STRING, p.nextToken());
62+
assertEquals("v3", p.getString());
63+
assertToken(JsonToken.PROPERTY_NAME, p.nextToken());
64+
assertEquals(KEY_2, p.currentName());
65+
assertToken(JsonToken.VALUE_STRING, p.nextToken());
66+
assertEquals("v4", p.getString());
67+
assertToken(JsonToken.END_OBJECT, p.nextToken());
68+
}
69+
70+
// Then, nextName() variants
71+
try (JsonParser p = createParser(mode, DOC_1491)) {
72+
assertToken(JsonToken.START_OBJECT, p.nextToken());
73+
assertTrue(p.nextName(new SerializedString(KEY_1)));
74+
assertToken(JsonToken.PROPERTY_NAME, p.currentToken());
75+
assertEquals(KEY_1, p.currentName());
76+
assertToken(JsonToken.VALUE_STRING, p.nextToken());
77+
assertEquals("v3", p.getString());
78+
assertTrue(p.nextName(new SerializedString(KEY_2)));
79+
assertToken(JsonToken.PROPERTY_NAME, p.currentToken());
80+
assertEquals(KEY_2, p.currentName());
81+
assertToken(JsonToken.VALUE_STRING, p.nextToken());
82+
assertEquals("v4", p.getString());
83+
assertToken(JsonToken.END_OBJECT, p.nextToken());
84+
}
85+
86+
try (JsonParser p = createParser(mode, DOC_1491)) {
87+
assertToken(JsonToken.START_OBJECT, p.nextToken());
88+
// try wrong match
89+
assertFalse(p.nextName(new SerializedString(KEY_2)));
90+
assertToken(JsonToken.PROPERTY_NAME, p.currentToken());
91+
assertEquals(KEY_1, p.currentName());
92+
assertToken(JsonToken.VALUE_STRING, p.nextToken());
93+
assertEquals("v3", p.getString());
94+
assertFalse(p.nextName(new SerializedString(KEY_1)));
95+
assertToken(JsonToken.PROPERTY_NAME, p.currentToken());
96+
assertEquals(KEY_2, p.currentName());
97+
assertToken(JsonToken.VALUE_STRING, p.nextToken());
98+
assertEquals("v4", p.getString());
99+
assertToken(JsonToken.END_OBJECT, p.nextToken());
100+
}
101+
}
102+
103+
@Test
104+
void test1491ViaMatcherBytes() throws Exception {
105+
JsonFactory f = newStreamFactory();
106+
_testViaMatcher(f, MODE_INPUT_STREAM);
107+
_testViaMatcher(f, MODE_INPUT_STREAM_THROTTLED);
108+
}
109+
110+
@Test
111+
void test1491ViaMatcherChar() throws Exception {
112+
JsonFactory f = newStreamFactory();
113+
_testViaMatcher(f, MODE_READER);
114+
}
115+
116+
private void _testViaMatcher(JsonFactory f, int mode) throws Exception
117+
{
118+
PropertyNameMatcher matcher = f.constructNameMatcher(List.of(NAMED_1, NAMED_2),
119+
false);
120+
121+
try (JsonParser p = createParser(mode, DOC_1491)) {
122+
assertToken(JsonToken.START_OBJECT, p.nextToken());
123+
124+
assertEquals(0, p.nextNameMatch(matcher));
125+
assertToken(JsonToken.PROPERTY_NAME, p.currentToken());
126+
assertEquals(KEY_1, p.currentName());
127+
128+
assertToken(JsonToken.VALUE_STRING, p.nextToken());
129+
assertEquals("v3", p.getString());
130+
131+
assertEquals(1, p.nextNameMatch(matcher));
132+
assertToken(JsonToken.PROPERTY_NAME, p.currentToken());
133+
assertEquals(KEY_2, p.currentName());
134+
135+
assertToken(JsonToken.VALUE_STRING, p.nextToken());
136+
assertEquals("v4", p.getString());
137+
assertToken(JsonToken.END_OBJECT, p.nextToken());
138+
}
139+
}
140+
}

0 commit comments

Comments
 (0)