在JsonNode中,asText()和toString()有什么区别?

14

所以我正在尝试在POST后验证一些有效载荷。

有效载荷(JSON)看起来像这样:

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

然后我尝试将上述内容转换为 JsonNode 并提取 "value" 的值。但是,asText()toString() 这两种方法返回不同的字符串值。

这两种方法有什么不同之处?

给定字符串 "\"<html><body><a href='http://www.example.com'>Hi there!</a></body></html>\""

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

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


2
第一个被序列化为JSON,第二个则不是。 - shmosel
@shmosel,好的,有道理。但是asText()方法序列化的结果是什么? - JACK ZHANG
它不是序列化的,只是一个字符串值。 - shmosel
4个回答

14

asText()是来自于JsonNode的抽象方法,它在TextNode中被覆盖。根据其实现方式,它应该返回未经任何操作的值。

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

toString()

此方法从Object中重写而来,因此它是一个对象的文本表示形式。因此,toString实际上会返回给您所提供对象的完整文本形式。根据在TextNode中实现的方式,它会在您的值之前和之后添加引号。

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

当你打印它们时,你也可以看到相同的差异。


我认为这是有道理的。因此,当有效载荷被序列化为JSON时,实际值成为HTML字符串,asText()返回它本身,而toString()将在HTML字符串周围添加引号。我理解得对吗? - JACK ZHANG
2
@JackZhang 是的,这正是我所说的。 - Ravi

3

我想补充的一点是,如果字符串非常长,对于我来说,只使用.toString()有效,而其他两个方法(.asText().textValue())将分别返回空字符串和null。


2

简而言之:

  • 只有主分支才具有被接受答案的行为;之前的版本,如Jackson 2.9,toString()不仅仅是“在字符串周围添加引号”。

  • 如果您想检查包含键值对(JSON对象)的JsonNode的文本表示形式,则必须使用toString()asText()将得到"",因为它不是ValueNode。在此过程中,Unicode(\uxxxx)将被转换为实际字符。

详细信息:

我使用我拥有的库进行了测试,然后发现我无法同意被接受的答案。我的版本是2.9。

在我的情况下,toString()不仅仅是添加引号。它还将保留字符串内容中的转义字符,至少从版本2.0到2.9。

请在此处查看源代码(注意URL中的版本。您可以在页面中选择版本,直到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()可以保留一些转义字符。在这里查看其源代码。(注意,该代码来自2.0分支,而非主分支)

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

但是,现在的master分支似乎将此行为简化为“仅添加引号”,就像接受的答案所说的那样。可以在此页面中看到这一点。实际上,此提交的标题为:

删除对CharTypes.appendQuoted()的依赖;将JsonNode.toString()的引号更改为单引号,以尝试防止用于JSON生成

但是,我正在使用2.9,CharTypes.appendQuoted()仍在使用中。因此,通常情况下,如果您没有使用主分支,则toString()将保留转义字符。

例如:

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.

因此,库版本不一定总是“主要版本”!


关于带有对象的 JsonNodetoString(),请参考以下内容:(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
}

0

asText()和toString()的区别

public abstract String asText()

如果节点是值节点(isValueNode()方法返回true),则该方法将返回容器值的有效字符串表示形式,否则返回空字符串。

public String readNameNode()
        {
            JsonNode nameNode=rootNode.path("name");
            String name=nameNode.asText();
            logger.info("\n----------------------------\nEmployee Name: "+name+"\n");
            return name;
        }

公共抽象字符串 toString()

注意:标记为抽象以确保所有实现类正确定义它。

覆盖:

public String readNameNode()
        {
            JsonNode nameNode=rootNode.path("name");
            String name=nameNode.toString();
            logger.info("\n----------------------------\nEmployee Name: "+name+"\n");
            return name;
        }

希望您已经明白了asText方法和toString方法之间的确切区别。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接