31

I have the following JSON string that i am sending to a NodeJS server:

String string = "{\"id\":\"" + userID + "\",\"type\":\"" + methoden + "\",\"msg\":\"" + msget + "\", \"name\":\"" + namnet + "\", \"channel\":\"" + activeChatChannel + "\", \"visitorNick\":\"\", \"agentID\":\" " + agentID + "\"}";

PrintWriter pw = new PrintWriter(new OutputStreamWriter(os, "utf-8"));
pw.println(string);

The problem becomes when the string msget contains the character " and '

On the NodeJS server i am parsing the JSON like this:

var obj = JSON.parse(message);

Any ideas how i can manage to send all characters without problems?

1

14 Answers 14

31

I would use a library to create your JSON String for you. Some options are:

This will make dealing with escaping much easier. An example (using org.json) would be:

JSONObject obj = new JSONObject();

obj.put("id", userID);
obj.put("type", methoden);
obj.put("msg", msget);

// etc.

final String json = obj.toString(); // <-- JSON string
Sign up to request clarification or add additional context in comments.

1 Comment

what if I don't want a builder and just the value string not the entire json?
27

Apache Commons

If you're already using Apache commons, it provides a static method for this:

StringEscapeUtils.escapeJson("some string")

It converts any string into one that's properly escaped for inclusion in JSON

See the documentation here

2 Comments

it is deprecated
It only moved to org.apache.commons.text.StringEscapeUtils so not deprecated if you use this one
25

The JSON specification at https://www.json.org/ is very simple by design. Escaping characters in JSON strings is not hard. This code works for me:

private String escape(String raw) {
    String escaped = raw;
    escaped = escaped.replace("\\", "\\\\");
    escaped = escaped.replace("\"", "\\\"");
    escaped = escaped.replace("\b", "\\b");
    escaped = escaped.replace("\f", "\\f");
    escaped = escaped.replace("\n", "\\n");
    escaped = escaped.replace("\r", "\\r");
    escaped = escaped.replace("\t", "\\t");
    // TODO: escape other non-printing characters using uXXXX notation
    return escaped;
}

Comments

18

org.json.simple.JSONObject.escape() escapes quotes,, /, \r, \n, \b, \f, \t and other control characters.

import org.json.simple.JSONValue;
JSONValue.escape("test string");

Add pom.xml when using maven

<dependency>
    <groupId>com.googlecode.json-simple</groupId>
    <artifactId>json-simple</artifactId>
    <scope>test</scope>
</dependency>

7 Comments

There is no such method escape.
Not java jsonObject. Look import in code. json-simple: code.google.com/archive/p/json-simple
JSONObject.quote(String) does the job.
|
12

The best method would be using some JSON library, e.g. Jackson ( http://jackson.codehaus.org ).

But if this is not an option simply escape msget before adding it to your string:

The wrong way to do this is

String msgetEscaped = msget.replaceAll("\"", "\\\"");

Either use (as recommended in the comments)

String msgetEscaped = msget.replace("\"", "\\\"");

or

String msgetEscaped = msget.replaceAll("\"", "\\\\\"");

A sample with all three variants can be found here: http://ideone.com/Nt1XzO

8 Comments

I didn't downvote, but the replaceAll() won't work. You need to use replace.
Have you tried the code you posted? It has no effect. Either you use replace(...) or replaceAll("\"", "\\\\\""), because the backslash has a special meaning in the replacement string, too. See javadoc.
I'm biased if i should delete this answer because it's wrong or if i should let it as is 'cause it shows how not to do it?
@DirkLachowski: If I were you, I'd either delete it (when I'm feeling lazy) or fix it.
@jlordo: I'm afraid you are wrong. The difference between replace() and replaceAll() is that in the former the first arg is a literal string and in the later it's a regex. The replacement is no regex (but can contain some special chars in the later). So replaceAll() will work as posted by me - and yes, i've tried it now.
|
6

According to the answer here, quotes in string content need to be escaped with a JSON string. You can do that by replacing quotes with \" in Java, like so

msget = msget.replace("\"", "\\\"");

If you're worried about other special characters, you can use a dedicated JSON parser to perform the transformation for you.

Jackson, for example, has JsonStringEncoder that accounts for all special characters.

If you're building the JSON manually, as in your sample code, you could do

String msget = "...";
JsonStringEncoder encoder = JsonStringEncoder.getInstance();
msget = new String(encoder.quoteAsUTF8(msget), StandardCharsets.UTF_8);

then plug the msget in to your output.

Comments

3

If you want to simply escape a string, not an object or array, use this:

String escaped = JSONObject.valueToString(" Quotes \" ' ' \" ");

http://www.json.org/javadoc/org/json/JSONObject.html#valueToString(java.lang.Object)

2 Comments

The link is broken, here is a web-archive version of it: web.archive.org/web/20151006021420/http://www.json.org/javadoc/…
Escaping only double quote is not enough.
2
public static String ecapse(String jsString) {
    jsString = jsString.replace("\\", "\\\\");
    jsString = jsString.replace("\"", "\\\"");
    jsString = jsString.replace("\b", "\\b");
    jsString = jsString.replace("\f", "\\f");
    jsString = jsString.replace("\n", "\\n");
    jsString = jsString.replace("\r", "\\r");
    jsString = jsString.replace("\t", "\\t");
    jsString = jsString.replace("/", "\\/");
    return jsString;
}

Comments

2

In build.gradle (if using maven, make similar change) include this dependency:

implementation group: 'org.apache.avro', name: 'avro-tools', version: '1.10.2'

Then:

import net.minidev.json.JSONValue;
String escapedString = JSONValue.escape(yourString);

Comments

2

If you can use slightly more modern Java and don't want another dependency, this does the job:

    static String jsonStringQuote(String string) {
        StringBuilder sb = new StringBuilder("\"");
        for (char c : string.toCharArray())
            sb.append(switch (c) {
                case '\\', '"', '/' -> "\\"+c;
                case '\b' -> "\\b";
                case '\t' -> "\\t";
                case '\n' -> "\\n";
                case '\f' -> "\\f";
                case '\r' -> "\\r";
                default -> c < ' ' ? String.format("\\u%04x", c) : c;
            });
        return sb.append('"').toString();
    }

Comments

2

On Android (and org.json), you could use JSONObject.quote.

import org.json.JSONObject;
String stringifiedString = JSONObject.quote(data);

Comments

1

If you want to do it yourself without any library, you can use this piece of Java code:

/**
 * Escapes a string the JSON way.
 *
 * @param text The text to be escaped.
 * @return a string escaped according to the JSON format.
 */
public static String escape(final CharSequence text) {

    if (text == null) {
        return "";
    }
    final StringWriter writer = new StringWriter();
    for (int i = 0, length = text.length(); i < length; i++) {
        final char c = text.charAt(i);
        switch (c) {
            case '"':
                writer.write("\\\"");
                break;
            case '\\':
                writer.write("\\\\");
                break;
            default:
                if (c > 0x1f) {
                    writer.write(c);
                } else {
                    writer.write("\\u");
                    final String hex = "000" + Integer.toHexString(c);
                    writer.write(hex.substring(hex.length() - 4));
                }
        }
    }
    return writer.toString();
}

Comments

0

Consider Moshi's JsonWriter class (source). It has a wonderful API and it reduces copying to a minimum, everything is nicely streamed to the OutputStream.

OutputStream os = ...;
JsonWriter json = new JsonWriter(Okio.sink(os));
json
  .beginObject()
  .name("id").value(userID)
  .name("type").value(methodn)
  ...
  .endObject();

Comments

0

Perhaps less efficient, but concise for the basic escapes without libraries using JDK 15+

  public static String escape(String s) {
    for (char c : "\\\"bfnrt".toCharArray())
      s = s.replace(("\\" + c).translateEscapes(), "\\" + c);
    return s;
  }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.