I use Jackson to generate JSON objects and write them directly into HTML's tag, like this:
<script>
var data = $SomeJacksonWrapper.toJson($data);
</script>
This code breaks if some string contains '</script>'
in it. Escaping forward slash (/) would solve the problem a开发者_Go百科nd it is alowed by JSON's spec.
How do I enable it in Jackson?
Using StaxMan's answer, I ended up with the following code:
public class CustomCharacterEscapes extends CharacterEscapes {
private static final Logger log = Logger.getLogger(CustomCharacterEscapes.class);
private final int[] _asciiEscapes;
public CustomCharacterEscapes() {
_asciiEscapes = standardAsciiEscapesForJSON();
_asciiEscapes['/'] = CharacterEscapes.ESCAPE_STANDARD;
}
@Override
public int[] getEscapeCodesForAscii() {
return _asciiEscapes;
}
@Override
public SerializableString getEscapeSequence(int i) {
return null;
}
}
public class CustomObjectMapper extends ObjectMapper {
public CustomObjectMapper() {
this.getJsonFactory().setCharacterEscapes(new CustomCharacterEscapes());
}
}
In addition to other suggestions, Jackson 1.8 also has "character escapes" feature, which allows redefining escaping rules. Documentation is lacking, but basically you need to implement CharacterEscapes
(see http://jackson.codehaus.org/1.8.2/javadoc/org/codehaus/jackson/io/CharacterEscape), register with JsonFactory (or directly JsonGenerator), and then escaping will be done according to whatever rules you want. In this case you could just change settings for '/' to use ESCAPE_STANDARD.
Additionally you could also add a feature request to add simple on/off feature, as this specific thing sounds like it might be useful for others as well. But has not yet been requested specifically as far as I know.
Thanks to StaxMan and Infeligo's answers here (cheers guys) I found a way to provide escaping for / to match the (IMHO horrible) WCF DataContractJsonSerializer date standard format:
/Date(1328053610008+1100)/
which requires the / to be escaped with a backslash resulting in the following across the wire:
\/Date(1328053610008+1100)\/
Just in case it may help someone else here is my CustomCharacterEscapes code that I used:
public class CustomCharacterEscapes extends CharacterEscapes {
private final int[] _asciiEscapes;
public CustomCharacterEscapes() {
_asciiEscapes = standardAsciiEscapesForJSON();
_asciiEscapes['/'] = CharacterEscapes.ESCAPE_CUSTOM;
}
@Override
public int[] getEscapeCodesForAscii() {
return _asciiEscapes;
}
@Override
public SerializableString getEscapeSequence(int i) {
if(i == '/'){
return new SerializableString() {
@Override
public String getValue() {
return "\\/";
}
@Override
public int charLength() {
return 2;
}
@Override
public char[] asQuotedChars() {
return new char[]{'\\','/'};
}
@Override
public byte[] asUnquotedUTF8() {
return new byte[]{'\\','/'};
}
@Override
public byte[] asQuotedUTF8() {
return new byte[]{'\\','/'};
}
};
}
else{
return null;
}
}
}
Kotlin version of a custom character escape for forward slashes:
/**
* Behaves like PHP json_encode() in that forward slashes are escaped.
*/
private class PhpCompatJsonEncode : CharacterEscapes() {
private val delegate = JsonpCharacterEscapes()
private val escapeForSlash = SerializedString("\\/")
private val asciiEscapes = standardAsciiEscapesForJSON()
init {
asciiEscapes['/'.code] = ESCAPE_CUSTOM
}
override fun getEscapeCodesForAscii(): IntArray {
return asciiEscapes
}
override fun getEscapeSequence(ch: Int): SerializableString? {
return when (ch) {
'/'.code -> escapeForSlash
else -> delegate.getEscapeSequence(ch)
}
}
}
This can also be configured per-writer, instead of globally in case this is only needed at a specific spot:
val writer: ObjectWriter = objectMapper.writer(PhpCompatJsonEncode())
精彩评论