Skip to content

Commit 8419cf8

Browse files
authored
fix: JSON builder string encoding of control characters (#69)
1 parent a949b55 commit 8419cf8

File tree

4 files changed

+56
-14
lines changed

4 files changed

+56
-14
lines changed

src/main/java/org/hisp/dhis/jsontree/JsonAppender.java

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -104,15 +104,26 @@ void appendEscaped( CharSequence str ) {
104104
return;
105105
}
106106
append( '"' );
107-
str.chars().forEachOrdered( c -> {
108-
if ( c == '"' || c == '\\' || c < ' ' ) {
109-
appendChar.accept( '\\' );
110-
}
111-
appendChar.accept( (char) c );
112-
} );
107+
str.chars().forEachOrdered( this::appendEscaped );
113108
append( '"' );
114109
}
115110

111+
private void appendEscaped( int c ) {
112+
switch ( c ) {
113+
case '\b' -> append( "\\b" );
114+
case '\f' -> append( "\\f" );
115+
case '\n' -> append( "\\n" );
116+
case '\r' -> append( "\\r" );
117+
case '\t' -> append( "\\t" );
118+
case '"' -> append( "\\\"" );
119+
case '\\' -> append( "\\\\" );
120+
case -31 -> append( "\\u%04X".formatted( c ) );
121+
case 0x2028 -> append( "\\u2028" );
122+
case 0x2029 -> append( "\\u2029" );
123+
default -> appendChar.accept( (char) c );
124+
}
125+
}
126+
116127
private void beginLevel( char c ) {
117128
append( c );
118129
hasChildrenAtLevel[++level] = false;

src/main/java/org/hisp/dhis/jsontree/JuonAppender.java

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -213,12 +213,23 @@ private void append(char c) {
213213

214214
void appendEscaped(@Surly CharSequence str ) {
215215
append( '\'' );
216-
str.chars().forEachOrdered( c -> {
217-
if ( c == '\'' || c == '\\' || c < ' ' ) {
218-
append( '\\' );
219-
}
220-
append( (char) c );
221-
} );
216+
str.chars().forEachOrdered( this::appendEscaped );
222217
append( '\'' );
223218
}
219+
220+
private void appendEscaped( int c ) {
221+
switch ( c ) {
222+
case '\b' -> append( "\\b" );
223+
case '\f' -> append( "\\f" );
224+
case '\n' -> append( "\\n" );
225+
case '\r' -> append( "\\r" );
226+
case '\t' -> append( "\\t" );
227+
case '\'' -> append( "\\'" );
228+
case '\\' -> append( "\\\\" );
229+
case -31 -> append( "\\u%04X".formatted( c ) );
230+
case 0x2028 -> append( "\\u2028" );
231+
case 0x2029 -> append( "\\u2029" );
232+
default -> append( (char) c );
233+
}
234+
}
224235
}

src/test/java/org/hisp/dhis/jsontree/JsonAppenderTest.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,25 @@ void testArray_JsonNode() {
269269
.addElement( JsonNode.of( "[\"a\",\"b\"]" ) ) ) );
270270
}
271271

272+
@Test
273+
void testNewlines() {
274+
//language=JSON
275+
String json = """
276+
{"id":"woOg1dUFoX0","time":1738685143915,"message":"com.fasterxml.jackson.core.JsonParseException: Unexpected character ('<' (code 60)): expected a valid value (JSON String, Number, Array, Object or token 'null', 'true' or 'false')\\n at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 1]","level":"ERROR"}""";
277+
JsonObject msg = JsonMixed.of( json );
278+
String message = msg.getString( "message" ).string();
279+
assertEquals( """
280+
com.fasterxml.jackson.core.JsonParseException: Unexpected character ('<' (code 60)): expected a valid value (JSON String, Number, Array, Object or token 'null', 'true' or 'false')
281+
at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 1]""",
282+
message );
283+
JsonObject actual = Json.object( obj ->
284+
obj.addString( "id", "woOg1dUFoX0" )
285+
.addNumber( "time", 1738685143915L )
286+
.addString( "message", message )
287+
.addString( "level", "ERROR" ));
288+
assertEquals( json, actual.toJson() );
289+
}
290+
272291
private static void assertJson( String expected, JsonNode actual ) {
273292
assertEquals( expected.replace( '\'', '"' ), actual.getDeclaration() );
274293
}

src/test/java/org/hisp/dhis/jsontree/JsonTest.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,9 @@ void testOf_Boolean() {
3535
void testOf_String() {
3636
assertJson( "null", Json.of( (String) null ) );
3737
assertJson( "\"hello\"", Json.of( "hello" ) );
38-
assertJson( "\"hello\\\n"
39-
+ "world\"", Json.of( "hello\nworld" ) );
38+
JsonString hello = Json.of( "hello\nworld" );
39+
assertJson( "\"hello\\nworld\"", hello );
40+
assertEquals( "hello\nworld", hello.string() );
4041
}
4142

4243
@Test

0 commit comments

Comments
 (0)