【问题标题】: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()方法序列化成什么结果呢?
  • 没有序列化。它只是一个字符串值。

标签: java json string


【解决方案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 方法之间的确切区别

      【讨论】:

        猜你喜欢
        • 2016-12-06
        • 1970-01-01
        • 2014-03-27
        • 1970-01-01
        • 1970-01-01
        • 2021-06-03
        • 1970-01-01
        • 2018-07-28
        • 2021-07-18
        相关资源
        最近更新 更多