从LinkedHashMap中获取值

3

我有一个长这样的对象:

{
/test1: {
  get: {
   tags: [
     "restcalls"
   ]
 }
},
/test2: {
  put: {
   tags: [
     "restcalls"
   ]
 }
}
}

我是这样检索上述对象的: ```

我是这样检索上述对象的:

```
HashMap<?, ?> json = new ObjectMapper().readValue(str, HashMap.class);

但是,检索标签并将其替换为其他关键词,比如"我的REST调用",最好的方法是什么?请注意,get、put可以是任何其他变量名,因此它是动态的,但是标签始终在get、put下面。


不要使用 HashMap。请使用 TreeNode 并适当地遍历它。 - Sotirios Delimanolis
你能提供一个例子并解释为什么要使用TreeNode吗? - fscore
既然您已经在使用对象映射器将JSON转换,为什么不将每个测试对象转换为一个真正的“TestObject” POJO,该POJO包含一个持有标签数组的“Method”对象?遍历复杂的对象图可能在未来难以维护。我使用Commons BeanUtils (http://commons.apache.org/proper/commons-beanutils)将对象从一种类型转换为另一种类型,如果您希望,我很乐意提供示例。 - johnnieb
2个回答

4

您已经选择了Jackson作为您的Java-JSON库(我可以说这是一个不错的选择),因此您手头的问题是如何最好地使用Jackson遍历和更新JSON,但是那些甚至在决定使用哪个Java-JSON库的人可以阅读此处,其中比较了以下7个Java-JSON库。以下是链接的结论摘录:

总之,如果您知道您的应用程序中只使用了少量的数据并且希望将其存储或读取到JSON格式中,则应考虑使用Flexjson或Gson。如果您将使用大量的数据并且希望将其存储或读取到JSON格式中,则应考虑使用Jackson或JSON-lib

  • Jackson(Java库)
  • Google-GSON(Java库)
  • JSON-lib(Java库)
  • Flexjson(Java库)
  • json-io(Java库)
  • genson(Java库)
  • JSONiJ(Java库)


Jackson

最重要的是要理解,Jackson 提供了三种处理 JSON 的替代方法(在这里阅读更多),因此应根据具体要求明智地选择适当的方法。

  1. 流式API(又称“增量解析/生成”):它将JSON内容作为离散事件读取和写入。 最佳用途:迭代事件(或令牌)流。 类似于:SAX和Stax

  2. 树模型:它提供了一个可变的JSON文档内存树表示形式。树模型类似于XML DOM。 最佳用途:将Json数据绑定到Java对象。 类似于:JAXB

  3. 数据绑定:它基于属性访问器约定或注释将JSON转换为POJOs,并从POJOs转换为JSON。有两个变体:简单和完全数据绑定。 最佳用途:使用合适的方法构建树结构(从Json中)并遍历它。 类似于:DOM

    • 简单数据绑定是指将Java Maps、Lists、Strings、Numbers、Booleans和nulls转换为JSON,反之亦然
    • 完全数据绑定是指将任何Java bean类型(以及上述“简单”类型)转换为JSON,反之亦然
通常使用“树模型”方法被认为是从“性能角度”最好的选择,因为它具有遍历树的优势。
其他选项也有其自身的优点,例如“流API具有较少的内存和CPU开销”,而“数据绑定易于使用”,因为它提供了JSON数据的“列表”和“映射”表示。然而,随着如此多的处理能力和内存,现在真正重要的是性能。
如果您的JSON数据很大,那么分析树表示中的树是否具有更宽的宽度或更长的长度。如果它具有更宽的宽度,则肯定使用“树模型”将具有与树处理相关的性能优势(确保您正在映射块而不是整个内容)。但是,如果树更长,意味着它没有很好的宽度,而是像一个非常长的尾巴,那么考虑使用“流API”,因为在这种情况下,无法证实树处理的优势。如果数据很小,则几乎没有关系,您可以将“树模型”用作默认设置。

目前您正在使用“数据绑定”方法,但建议使用“树模型”,因为您所需的只是JSON的遍历和操作。从您提供的信息来看,似乎您不需要将JSON转换为Java对象,因此“数据绑定”方法似乎不是一个好主意。

Jackson Tree Model

com.fasterxml.jackson.databind.JsonNode是Jackson树模型的基础。 将Jackson的树模型视为HTML文档的DOM,就像DOM在树结构中表示完整的HTML文档一样,Jackson的树模型表示完整的JSON字符串。

以下是可以帮助您使用Jackson树模型并实现您要查找的内容的代码:

import java.io.IOException;
import java.util.Iterator;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;


public class Test {

    public static void main(String[] args) throws JsonProcessingException, IOException {
        String jsonString = "{\"test1\": {\"get\": {\"tags\": [\"restcalls1\"]}}, \"test2\": {\"put\": {\"tags\": [\"restcalls2\"] }}}";
        ObjectMapper objectMapper = new ObjectMapper();
        JsonNode rootNode = objectMapper.readTree(jsonString);

        Iterator<JsonNode> iterator2 = rootNode.iterator();
        while (iterator2.hasNext()) {
            JsonNode node2 = iterator2.next().findParent("tags");
            ObjectNode objectNode = (ObjectNode) node2;
            objectNode.putArray("tags").add("my rest calls");
        }

        Iterator<JsonNode> iterator = rootNode.iterator();
        while (iterator.hasNext()) {
            JsonNode node2 = iterator.next();
            System.out.println(node2);
        }

    }
}

树形模型的优点:

点击这里了解更多细节

  • 如果Json内容的结构高度不规则,则可能难以找到或创建等效的Java对象结构。树形模型可能是唯一实际的选择。
  • 对于显示任何JSON内容,树形模型是内部访问和操作的自然选择。
  • 由于我们不需要特定的Java对象来绑定,因此可能需要编写较少的代码。

进一步阅读:


根据 OP 的评论:

以下代码展示了如何遍历并打印整个 JSON。通过这种方式,您可以遍历整个 JSON,然后访问您正在寻找的元素。需要注意的关键是,即使您使用 Stream API 方法,您也需要知道元素名称才能查找,参见 Stream API 示例 here

无论如何,您总是可以选择遍历整个 JSON(如下面的示例所示)或进行特定和直接的操作(如上面的示例所示)

package com.him.services;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;


public class Test {

    public static void main(String[] args) throws JsonProcessingException, IOException {
        jacksonTest();
    }

    private static void jacksonTest() throws JsonProcessingException, IOException {
        String jsonString = "{\"test1\": {\"get\": {\"tags\": [\"restcalls1\"]}}, \"test2\": {\"put\": {\"tags\": [\"restcalls2\"] }}}";
        ObjectMapper objectMapper = new ObjectMapper();
        JsonNode rootNode = objectMapper.readTree(jsonString);
        ArrayList<JsonNode> nodeList = new ArrayList<JsonNode>();
        nodeList.add(rootNode);

        printCompleteJson(nodeList);
    }

    private static void printCompleteJson(ArrayList<JsonNode> rootNode) throws IOException {
        for (int i = 0; i < rootNode.size(); i++) {
            Iterator<JsonNode> iterator = rootNode.get(i).iterator();
            JsonNode node = null;
            ArrayList<JsonNode> nodeList = new ArrayList<JsonNode>();
            boolean isEmpty = true;
            while (iterator.hasNext()) {
                isEmpty = false;
                node = iterator.next();
                nodeList.add(node);
                System.out.println(node);
            }
            if(isEmpty){
                return;
            }
            printCompleteJson(nodeList);
        }
    }
}

但是getput可以是任何HTTP动词,因此我不想明确指定检索值,而是自动检测它。 - fscore
我试图向您介绍更多的核心概念,这样一旦您掌握了这些概念,小的调整或需求变更就不应该成为问题。我已经编辑了我的答案来解决您的问题。如有任何疑问,请告诉我。基本上,您应该了解使用Jackson或任何其他库可以以多少种不同的方式实现相同的事情。您所需要做的就是选择一种方法并阅读其文档,以了解其中可用的API,然后使用它来实现您的要求。 - hagrawal7777
你好,有什么问题需要解答吗? - hagrawal7777
谢谢。您能否详细说明一下您对“http动词”的担忧,现在还不清楚...那是一个JSON,它不仅包含HTTP方法名称,还可能包含一些协议名称...使用“Jackson”和类似的JSON序列化和反序列化库,您可以遍历这个东西... - hagrawal7777
这正是我所说的,我不知道它将是test1->get->tags还是test2->post->tags或test3->put->tags。 - fscore
显示剩余4条评论

0
你可以使用Jackson的JsonNode类来遍历整个JSON并更改标签的节点值。请参见下面的代码:
public class Tags {

    public static void main(String[] args) throws Exception {
        InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("tags.json");
        ObjectMapper om = new ObjectMapper();
        JsonNode node = om.readTree(in);
        recursiveFind(node);
        System.out.println(node); //Prints {"test1":{"get":{"tags":["my rest calls"]}},"test2":{"put":{"tags":["my rest calls"]}}}
    }

    private static void recursiveFind(JsonNode node) {
        if (!node.isObject()) {
            return;
        }

        JsonNode tags = node.get("tags");
        if (tags != null) {
            ArrayNode arry = (ArrayNode) tags;
            arry.removeAll();
            arry.add("my rest calls");
        }

        Iterator<JsonNode> it = node.elements();
        while (it.hasNext()) {
            JsonNode jsonNode = it.next();
            recursiveFind(jsonNode);
        }
    }
}

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