JSONUtil { private static String escapeBadIdentifierCodePoints( String propertyName, JSONConfig cfg ) { boolean useSingleLetterEscapes = cfg.isFullJSONIdentifierCodePoints(); boolean processInlineEscapes = true; StringProcessor cp = new StringProcessor(propertyName, cfg, useSingleLetterEscapes, processInlineEscapes); if ( cp.isNoProcessing() && isValidJavascriptPropertyNameImpl(propertyName, cfg) ){ return propertyName; } StringBuilder buf = new StringBuilder(propertyName.length()+20); while ( cp.nextReady() ){ String esc = cp.getEscape(); if ( esc != null ){ buf.append(esc); }else if ( cp.getIndex() > 0 && isValidIdentifierPart(cp.getCodePoint(), cfg) ){ cp.appendChars(buf); }else if ( cp.getIndex() == 0 && isValidIdentifierStart(cp.getCodePoint(), cfg) ){ cp.appendChars(buf); }else{ buf.append(cp.getEscapeString()); } } return buf.toString(); } private  JSONUtil(); static String toJSON( Object obj ); static String toJSON( Object obj, JSONConfig cfg ); static void toJSON( Object obj, Writer json ); static void toJSON( Object obj, JSONConfig cfg, Writer json ); static Set<String> getJavascriptReservedWords(); static boolean isReservedWord( String name ); static void checkValidJavascriptPropertyName( String propertyName, JSONConfig cfg ); static void checkValidJavascriptPropertyName( String propertyName ); static boolean isValidJavascriptPropertyName( String propertyName, JSONConfig cfg ); static boolean isValidJavascriptPropertyName( String propertyName );  }
@Test public void testEscapeBadIdentifierCodePoints() throws ScriptException, NoSuchMethodException { Map<Object,Object> jsonObj = new LinkedHashMap<>(); StringBuilder buf = new StringBuilder("c"); StringBuilder cmpBuf = new StringBuilder(); JSONConfig cfg = new JSONConfig().setEscapeBadIdentifierCodePoints(true); jsonObj.put("x\u0005", 0); String json = JSONUtil.toJSON(jsonObj, cfg); validateJSON(json); assertThat(json, is("{\"x\\u0005\":0}")); for ( int i = 0; i < 256; i++ ){ buf.setLength(0); buf.append("c").append((char)i); jsonObj.clear(); jsonObj.put(String.format("a\\%o", i), 0); jsonObj.put(String.format("b\\x%02X", i), 0); jsonObj.put(buf, 0); json = JSONUtil.toJSON(jsonObj, cfg); validateJSON(json); String r = JSONUtil.isValidIdentifierPart(i, cfg) ? String.format("%c", (char)i) : String.format("\\u%04X", i); assertThat(json, is("{\"a"+r+"\":0,\"b"+r+"\":0,\"c"+r+"\":0}")); } int maxLen = 512; buf.setLength(0); buf.append("c"); cmpBuf.setLength(0); cmpBuf.append("{\"c"); for ( int i = 256, ct = 0; i <= Character.MAX_CODE_POINT; i++ ){ if ( isNormalCodePoint(i) ){ buf.appendCodePoint(i); addCmp(i, cmpBuf, cfg); ++ct; } if ( ct % maxLen == 0 || i == Character.MAX_CODE_POINT ){ jsonObj.clear(); jsonObj.put(buf, 0); json = JSONUtil.toJSON(jsonObj, cfg); validateJSON(json); cmpBuf.append("\":0}"); assertThat(json, is(cmpBuf.toString())); buf.setLength(0); buf.append("c"); cmpBuf.setLength(0); cmpBuf.append("{\"c"); } } cfg.setFullJSONIdentifierCodePoints(true); for ( int i = 0; i < 256; i++ ){ buf.setLength(0); buf.append("c").append((char)i); jsonObj.clear(); jsonObj.put(String.format("a\\%o", i), 0); jsonObj.put(String.format("b\\x%02X", i), 0); jsonObj.put(buf, 0); json = JSONUtil.toJSON(jsonObj, cfg); validateJSON(json); String r = StringProcessor.getEscape((char)i); if ( r == null ){ r = JSONUtil.isValidIdentifierPart(i, cfg) ? String.format("%c", (char)i) : String.format("\\u%04X", i); } assertThat(json, is("{\"a"+r+"\":0,\"b"+r+"\":0,\"c"+r+"\":0}")); } buf.setLength(0); buf.append("c"); for ( int i = 256, ct = 0; i <= Character.MAX_CODE_POINT; i++ ){ if ( isNormalCodePoint(i) ){ buf.appendCodePoint(i); addCmp(i, cmpBuf, cfg); ++ct; } if ( ct % maxLen == 0 || i == Character.MAX_CODE_POINT ){ jsonObj.clear(); jsonObj.put(buf, 0); json = JSONUtil.toJSON(jsonObj, cfg); parseJSON(json); cmpBuf.append("\":0}"); assertThat(json, is(cmpBuf.toString())); buf.setLength(0); buf.append("c"); cmpBuf.setLength(0); cmpBuf.append("{\"c"); } } }