开发者

Escape forward slash in Jackson

开发者 https://www.devze.com 2023-03-23 06:02 出处:网络
I use Jackson to generate JSON objects and write them directly into HTML\'stag, like this: <script>

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())
0

精彩评论

暂无评论...
验证码 换一张
取 消