27

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?

Alosyius
  • 8,771
  • 26
  • 76
  • 120

14 Answers14

30

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
jabclab
  • 14,786
  • 5
  • 54
  • 51
22

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;
}
Ron DeSantis
  • 855
  • 7
  • 5
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>
NoobEditor
  • 15,563
  • 19
  • 81
  • 112
Yeongjun Kim
  • 739
  • 7
  • 19
18

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

davnicwil
  • 28,487
  • 16
  • 107
  • 123
11

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

Dirk Lachowski
  • 3,121
  • 4
  • 40
  • 66
  • 1
    I didn't downvote, but the `replaceAll()` won't work. You need to use `replace`. – Sotirios Delimanolis Sep 19 '13 at 15:32
  • 1
    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. – jlordo Sep 19 '13 at 15:33
  • 1
    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? – Dirk Lachowski Sep 19 '13 at 15:36
  • @DirkLachowski: If I were you, I'd either delete it (when I'm feeling lazy) or fix it. – jlordo Sep 19 '13 at 15:37
  • @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. – Dirk Lachowski Sep 19 '13 at 15:53
  • @DirkLachowski: You're right that `replace()` takes a literal and `replaceAll()` takes a regex. But if you use `replaceAll()` you have to use it as I posted in my comment. See http://ideone.com/XhDeaT Yours won't work. – jlordo Sep 19 '13 at 16:42
  • @jlordo: Thumbs up for getting back on this and for the link to idone.com. Didn't knowed that before. I got it now, thanks for the lesson. – Dirk Lachowski Sep 19 '13 at 17:36
  • @DirkLachowski: removed my -1, as the answer is now correct ;) – jlordo Sep 20 '13 at 09:40
4

According to the answer here, quotes in values need to be escaped. You can do that with \"

So just repalce the quote in your values

msget = msget.replace("\"", "\\\"");
Community
  • 1
  • 1
Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
4

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)

rhengles
  • 41
  • 2
  • The link is broken, here is a web-archive version of it: https://web.archive.org/web/20151006021420/http://www.json.org/javadoc/org/json/JSONObject.html – Renato Mar 29 '23 at 20:51
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;
}
Sagar Jadhav
  • 1,111
  • 11
  • 10
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);
Tai Meng
  • 41
  • 2
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();
}
gil.fernandes
  • 12,978
  • 5
  • 63
  • 76
1

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();
    }

Matthew Bloch
  • 357
  • 2
  • 10
0

Try to replace all the " and ' with a \ before them. Do this just for the msget object(String, I guess). Don't forget that \ must be escaped too.

Silviu Burcea
  • 5,103
  • 1
  • 29
  • 43
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();
orip
  • 73,323
  • 21
  • 116
  • 148
0

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

import org.json.JSONObject;
String stringifiedString = JSONObject.quote(data);
FredG
  • 712
  • 7
  • 10