21

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,231
  • 26
  • 72
  • 116

12 Answers12

29

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,220
  • 5
  • 49
  • 49
19

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
  • 755
  • 6
  • 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
  • 14,879
  • 17
  • 75
  • 106
Yeongjun Kim
  • 709
  • 6
  • 17
15

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
  • 24,731
  • 13
  • 95
  • 108
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,083
  • 4
  • 40
  • 65
  • 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
  • 263,859
  • 56
  • 671
  • 702
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
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,019
  • 9
  • 9
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
  • 31
  • 2
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
  • 4,689
  • 1
  • 27
  • 42
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
  • 69,626
  • 21
  • 116
  • 145
0

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
  • 11,381
  • 5
  • 51
  • 69