JsonNode 中的 asText() 和 toString() 有啥区别?

Posted

技术标签:

【中文标题】JsonNode 中的 asText() 和 toString() 有啥区别?【英文标题】:What is the difference between asText() and toString() in JsonNode?JsonNode 中的 asText() 和 toString() 有什么区别? 【发布时间】:2018-07-17 05:28:05 【问题描述】:

所以我试图在 POST 之后验证一些有效负载。

有效负载 (JSON) 如下所示:

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

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

这两种方法的工作方式有何不同?

给定字符串"\"&lt;html&gt;&lt;body&gt;&lt;a href='http://www.example.com'&gt;Hi there!&lt;/a&gt;&lt;/body&gt;&lt;/html&gt;\""

toString 返回"&lt;html&gt;&lt;body&gt;&lt;a href='http://www.example.com'&gt;Hi there!&lt;/a&gt;&lt;/body&gt;&lt;/html&gt;"

asText() 返回&lt;html&gt;&lt;body&gt;&lt;a href='http://www.example.com'&gt;Hi there!&lt;/a&gt;&lt;/body&gt;&lt;/html&gt;

【问题讨论】:

第一个序列化为JSON,第二个不是。 @shmosel,好吧,这是有道理的。但是asText()方法序列化成什么结果呢? 没有序列化。它只是一个字符串值。 【参考方案1】:

我要补充的一点是,如果字符串很长,对我来说,只使用.toString(),因为其他两个(.asText().textValue())将分别返回空字符串和 null。

【讨论】:

【参考方案2】:

TL;DR:

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

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

详细说明:

我用我拥有的库进行了测试,然后我发现我不能同意接受的答案。我的是2.9。

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

查看来源here(注意网址中的版本,可以在页面中选择版本,直到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() 将保留一些转义字符。在here查看它的源代码。(注意代码来自2.0分支,不是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);
        
    

但是,正如接受的答案所说,现在master 分支似乎将此行为简化为“仅添加引号”。这可以在this page 中看到。实际上,这个提交的标题是

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

但同样,我使用的是 2.9,而CharTypes.appendQuoted() 仍在使用。因此,通常情况下,如果您不使用 master 分支,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.

因此,注意 lib 版本并不总是“大师”!


对于带有对象的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

【讨论】:

【参考方案3】:

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

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

【讨论】:

我认为这是有道理的。所以当payload被序列化为JSON时,实际值变成了html字符串,asText()按原样返回,toString()会在html字符串两边加上引号。我理解正确吗? @JackZhang 是的,这正是我所说的。【参考方案4】:

asText() 和 toString() 的区别

公共抽象字符串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()

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

覆盖: 类中的 toString

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

希望你理解 asText 方法和 toString 方法之间的确切区别

【讨论】:

以上是关于JsonNode 中的 asText() 和 toString() 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

Jackson 中的 ObjectNode 和 JsonNode 有啥区别?

如何检查 JsonNode 是 Java 中的单个元素还是数组?

如何将 JSON 字符串解析为 Jackson 中的 JsonNode?

将 JsonNode 转换为 POJO

介绍Jackson JsonNode和ObjectNode

JOOQ 代码生成器跳过包含 JsonNode 字段的类