@@ -48,6 +48,38 @@ public class JsonOutput implements Closeable {
48
48
private static final Logger LOG = Logger .getLogger (JsonOutput .class .getName ());
49
49
private static final int MAX_DEPTH = 5 ;
50
50
51
+ // https://www.json.org has some helpful comments on characters to escape
52
+ // See also https://tools.ietf.org/html/rfc8259#section-7 and
53
+ // https://github.com/google/gson/issues/341 so we escape those as well.
54
+ // It's legal to escape any character, so to be nice to HTML parsers,
55
+ // we'll also escape "<" and "&"
56
+ private static final Map <Integer , String > ESCAPES ;
57
+ static {
58
+ ImmutableMap .Builder <Integer , String > builder = ImmutableMap .builder ();
59
+
60
+ for (int i = 0 ; i <= 0x1f ; i ++) {
61
+ // We want nice looking escapes for these, which are called out
62
+ // by json.org
63
+ if (!(i == '\b' || i == '\f' || i == '\n' || i == '\r' || i == '\t' )) {
64
+ builder .put (i , String .format ("\\ u%04x" , i ));
65
+ }
66
+ }
67
+
68
+ builder .put ((int ) '"' , "\\ \" " );
69
+ builder .put ((int ) '\\' , "\\ \\ " );
70
+ builder .put ((int ) '/' , "\\ u002f" );
71
+ builder .put ((int ) '\b' , "\\ b" );
72
+ builder .put ((int ) '\f' , "\\ f" );
73
+ builder .put ((int ) '\n' , "\\ n" );
74
+ builder .put ((int ) '\r' , "\\ r" );
75
+ builder .put ((int ) '\t' , "\\ t" );
76
+
77
+ builder .put ((int ) '\u2028' , "\\ u2028" );
78
+ builder .put ((int ) '<' , String .format ("\\ u%04x" , (int ) '<' ));
79
+ builder .put ((int ) '&' , String .format ("\\ u%04x" , (int ) '&' ));
80
+ ESCAPES = builder .build ();
81
+ }
82
+
51
83
private final Map <Predicate <Class <?>>, SafeBiConsumer <Object , Integer >> converters ;
52
84
private final Appendable appendable ;
53
85
private final Consumer <String > appender ;
@@ -238,24 +270,11 @@ private JsonOutput append(String text) {
238
270
}
239
271
240
272
private String asString (Object obj ) {
241
- // https://www.json.org has some helpful comments on characters to escape
242
273
StringBuilder toReturn = new StringBuilder ("\" " );
243
274
244
275
String .valueOf (obj )
245
276
.chars ()
246
- .mapToObj (
247
- i -> {
248
- switch (i ) {
249
- case '"' : return "\\ \" " ;
250
- case '\\' : return "\\ \\ " ;
251
- case '\b' : return "\\ b" ;
252
- case '\f' : return "\\ f" ;
253
- case '\n' : return "\\ n" ;
254
- case '\r' : return "\\ r" ;
255
- case '\t' : return "\\ t" ;
256
- default : return "" + (char ) i ;
257
- }
258
- })
277
+ .mapToObj (i -> ESCAPES .getOrDefault (i , "" + (char ) i ))
259
278
.forEach (toReturn ::append );
260
279
261
280
toReturn .append ('"' );
0 commit comments