2

I am attempting to escape a string in a JSP to return valid JSON on an AJAX call however the spring:escapeBody tag is not correctly escaping single quotes for JSON. Valid JSON should not escape single quotes.

<%@ page trimDirectiveWhitespaces="true" contentType="json/application"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
{
"status": "success",
"body" : "<spring:escapeBody javaScriptEscape="true"> 
           if you don't have "user" an account
           </spring:escapeBody>"
 }

so this code evaluates to:

{
"status": "success",
"body" : "if you don\'t have \"user\" an account"
 }

but valid JSON needs it to be:

{
"status": "success",
"body" : "if you don't have \"user\" an account"
 }

is there anyway I can not escape the single quote with the escapeBody tag? Or is there another tag I can use? maybe a JSTL function?

Ryan
  • 414
  • 1
  • 6
  • 16
  • 2
    This is a very unusual way to get a JSON response. Why are you not returning a object from a controller and let Jackson handle the JSON writing? – Bart Aug 25 '14 at 17:46
  • This is a slight simplification of my actual code, I am actually attempting to return a existing tag file in the body of the JSON Object (the tag contains single quotes that aren't escaping). Would I be able to escape a tag file correctly in the controller and then return the escaped HTML/Javascript? – Ryan Aug 25 '14 at 18:09
  • @Bart thanks for pointing out the fact that this is an unsual way to get a JSON response. I guess everyone should stay away from `spring:escapeBody` and look into "Java to JSON best practices" and "java to json best libraries", ie http://stackoverflow.com/questions/7539954/java-json-serialization-best-practice – Adriano Sep 23 '14 at 11:11

2 Answers2

3

The Javascript Object Notation specification states that

Any character may be escaped.

As such,

{
    "status": "success",
    "body" : "if you don\'t have \"user\" an account"
}

is valid JSON.

If you need to create really custom text, you'll need to generate it yourself in a controller handler method or other component.

Ideally, you would use a @ResponseBody annotated method with a POJO that represents your status/body JSON object.

Community
  • 1
  • 1
Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
  • 1
    Thats what I assumed as well however if you paste that json into any json parser it will throw an error on the escaped single quote, as will your browser. – Ryan Aug 25 '14 at 18:00
  • 1
    @Ryan [This jsfiddle snippet](http://jsfiddle.net/wtkqhsLy/2/) works just fine, so does parsing the same JSON with Gson, Jackson, and org.json. I'll accept that jsonlint fails, but that seems like a bug. – Sotirios Delimanolis Aug 25 '14 at 18:06
  • 1
    @Ryan Basically, `'` doesn't need to be escaped, but it _can_. `escapeBody` is not the right tool for this. Use a proper serialization component. A JSON view or `@ResponseBody` with an appropriate POJO. If the JSP needs to be imported by another, create your own tag or generate the JSON and add it to the model. – Sotirios Delimanolis Aug 25 '14 at 18:17
  • 1
    your right, I guess my issue is that jQuery is being picky about it. http://stackoverflow.com/questions/2275359/jquery-single-quote-in-json-response – Ryan Aug 25 '14 at 18:18
  • @SotiriosDelimanolis - Yes, but *May* is interpreted per [RFC 2119](http://tools.ietf.org/html/rfc2119): `This word, or the adjective "OPTIONAL", mean that an item is truly optional`. So JSON with an escaped single quote may be valid JSON, but it may not, depending upon the implementation. – Justin Ethier Sep 23 '14 at 13:59
  • @JustinEthier The same RFC states that there must be some interoperability between implementations that do and don't include it [the escaping of all characters]. There doesn't seem to be any here (jQuery and jsonlint). – Sotirios Delimanolis Sep 23 '14 at 14:44
  • @SotiriosDelimanolis - Yes, but it includes weasel words `though perhaps with reduced functionality`. If you try using your browser's `JSON.parse` function to parse `"\'"` it will raise a syntax error - perhaps that could be considered interop in the sense that it detects an unhandled case and reports an error. – Justin Ethier Sep 23 '14 at 15:39
  • @JustinEthier Bleh. I thought this spec was rock solid. – Sotirios Delimanolis Sep 23 '14 at 15:42
3

As pointed out by Ryan in the (very good) comments of Sotirios Delimanolis's answer:

So it seems like it's simply an implementation choice that is now leaving us with a standard that's not really consistently implemented... sigh

Anyway, here is a work around you can use to get your code working

<%@ page trimDirectiveWhitespaces="true" contentType="json/application"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%-- 
    [1] Removing the escape of the single quote character: jQuery's Ajax cannot handle it
            stackoverflow.com/questions/25491391/springescapebody-results-in-invalid-json
            stackoverflow.com/questions/2275359/jquery-single-quote-in-json-response
--%>
<c:set var="someJsonData" >
    <spring:escapeBody javaScriptEscape="true"> 
               if you don't have "user" an account
    </spring:escapeBody>
</c:set>    
{
    "status": "success",
    "body" : "${fn:replace(someJsonData, "\\\'","'")}" , <%-- [1] --%>
}

Here is the JSTL fn documentation

Probably not the cleanest/best solution to be honest. But it does the job until you find better.

Community
  • 1
  • 1
Adriano
  • 19,463
  • 19
  • 103
  • 140