Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between asText() and toString() in JsonNode?

Tags:

java

json

string

So I'm trying to validate some payload after POSTing.

The payload (JSON) looks like the follow:

{"value":"\"<html><body><a href='http://www.example.com'>Hi there!</a></body></html>\""}

Then I tried to convert the above to JsonNode and extract the "value"'s value. However, the two methods, asText() & toString(), return different string values.

How do these two methods work differently?

Given the String "\"<html><body><a href='http://www.example.com'>Hi there!</a></body></html>\""

toString returns "<html><body><a href='http://www.example.com'>Hi there!</a></body></html>"

asText() returns <html><body><a href='http://www.example.com'>Hi there!</a></body></html>

like image 944
JACK ZHANG Avatar asked Feb 07 '18 02:02

JACK ZHANG


3 Answers

asText ()

It is an abstract method from JsonNode, which is overriden in TextNode. And, as per its implementation, it supposed to return the value without any manipulation.

@Override
public String asText() {
    return _value;
}

toString ()

It is overridden from Object. So, it is textual representation of an object. So, toString actually returns you the complete textual form on your given object. And, per its implementation in TextNode. It appends quoting (at the beginning and end) to your value.

/**
 * Different from other values, Strings need quoting
 */
@Override
public String toString()
{
    int len = _value.length();
    len = len + 2 + (len >> 4);
    return new StringBuilder(len)
            // 09-Dec-2017, tatu: Use apostrophes on purpose to prevent use as JSON producer:
            .append('\'')
            .append(_value)
            .append('\'')
            .toString();
}

And, you can also see the same difference when you print them.

like image 115
Ravi Avatar answered Oct 22 '22 03:10

Ravi


TL;DR:

  • Only the master branch has the behaviour of the accepted answer; versions before that, like Jackson 2.9, toString() does more than just "adding quotations around the string".

  • If you want to check the text representation of some JsonNode which contains an key-value pair(an JSON object), you have to use toString(); asText() will get you "", because it is not a ValueNode. And, in this process, Unicode (\uxxxx) will be translated to actual characters.

In detail:

I tested with the lib I have and then I found I cannot agree with the accepted answer. Mine is 2.9.

In my case toString() does more than just add quotations. It will also perserve the escaping characters in the string content, at least from version 2.0 to 2.9.

Check the source here(mind the version in URL. You can choose the version in the page, till 2.10)

2.0:

/**
 * Different from other values, Strings need quoting
 */
@Override
public String toString()
{
    int len = _value.length();
    len = len + 2 + (len >> 4);
    StringBuilder sb = new StringBuilder(len);
    appendQuoted(sb, _value);
    return sb.toString();
}

protected static void appendQuoted(StringBuilder sb, String content)
{
    sb.append('"');
    CharTypes.appendQuoted(sb, content);
    sb.append('"');
}

fasterxml.jackson.core.io.CharTypes.appendQuoted() will perserve some escape characters. Check its source at here.(Note the code is from 2.0 branch, not master)

public static void appendQuoted(StringBuilder sb, String content)
{
    final int[] escCodes = sOutputEscapes128;
    int escLen = escCodes.length;
    for (int i = 0, len = content.length(); i < len; ++i) {
        char c = content.charAt(i);
        if (c >= escLen || escCodes[c] == 0) {
            sb.append(c);
            continue;
        }
        sb.append('\\');
        int escCode = escCodes[c];
        if (escCode < 0) { // generic quoting (hex value)
            // We know that it has to fit in just 2 hex chars
            sb.append('u');
            sb.append('0');
            sb.append('0');
            int value = -(escCode + 1);
            sb.append(HEX_CHARS[value >> 4]);
            sb.append(HEX_CHARS[value & 0xF]);
        } else { // "named", i.e. prepend with slash
            sb.append((char) escCode);
        }
    }
}

But, now the master branch seems to simplify this behaviour to "only adding quotations", just as the accepted answer said. This can be seen in this page. Actually, this commit has the title of

Remove dependency to CharTypes.appendQuoted(); change quotes of JsonNode.toString() to single quotes to try to prevent use for JSON generation

But again, I am using 2.9 and CharTypes.appendQuoted() is still used. So, normally, if you are not using the master branch, toString() will perserve the escaping characters.

Example:

JsonNode node = new TextNode("{\"en_us\":\"54\",\"es_es\":\"54\"}");
node.asText();  // -> {"en_us":"54","es_es":"54"}, no quotations, no escaping
node.toString(); // -> "{\"en_us\":\"54\",\"es_es\":\"54\"}", add quotations, perserves escaping.

So, mind with versions of lib is not always the "master"!


As for toString() of a JsonNode with object, check this:(Jackson data-bind 2.9)

@Test
public void testToString() {
    ObjectMapper mapper = new ObjectMapper();
    JsonNode node = mapper.createObjectNode();
    ((ObjectNode) node).put("es_es", "Categor\u00eda ra\u00edz/CATEGORY_OMS_DATA/");

    System.out.println((node.toString())); // {"es_es":"Categoría raíz/CATEGORY_OMS_DATA/"}, note: not quotations around!! not like TextNode!
    System.out.println(node.asText()); // empty
}
like image 2
WesternGun Avatar answered Oct 22 '22 04:10

WesternGun


One thing I will add is that if the string is very long, for me, only using .toString() worked as the other two (.asText() and .textValue()) would return empty string and null respectively.

like image 1
pixel Avatar answered Oct 22 '22 02:10

pixel