【问题标题】:Loop to generate JSON循环生成 JSON
【发布时间】:2020-10-10 08:19:22
【问题描述】:

我正在实现 Java SpringBoot 来制作 RestAPI 应用程序。我坚持下面的循环。问题似乎与 sub1_arr.add(subResult1);

我已经进行了一些测试:

  1. 为每次迭代打印 SubResult1:println 显示正确的元素,但是当添加到 sub1_arr 时,它变得重复。

  2. Test 1(如代码所示):这是假设我编写的初始代码。输出不正确,重复输出

  3. 测试 2(如代码所示):输出正确,但为字符串形式。

    while(rs.next())
    {
        if(rs.getString("status").equals("FAILED")) {
            obj.put("result", "failed"); 
            obj.put("msg", rs.getString("msg"));
        } 
        else {

            //mainResult - ignore for a while
            mainResult.put("layer1_id", rs.getString("layer1_id"));
            mainResult.put("layer1_name", rs.getString("layer1_name"));

            //subResult - layer2
            subResult1.put("layer2_id", rs.getString("layer2_id"));
            subResult1.put("layer2_name", rs.getString("layer2_name"));

            //test 1 - having incorrect output with all the element become duplicate
            sub1_arr.add(subResult1);

            //test 2 - having correct output but the output become string with \"xxx\"
            sub1_arr.add(subResult1.toString());
        }

    }

    //adding sub array to main result
    mainResult.set("layer2", sub1_arr);

获取输出(意外)

{"layer2":[
   {"layer2_id" : "3", "layer2_name" : "name_3"},
   {"layer2_id" : "3", "layer2_name" : "name_3"},
   {"layer2_id" : "3", "layer2_name" : "name_3"} 
]}

预期输出

{"layer2":[
   {"layer2_id" : "1", "layer2_name" : "name_1"},
   {"layer2_id" : "2", "layer2_name" : "name_2"},
   {"layer2_id" : "3", "layer2_name" : "name_3"} 
]}

【问题讨论】:

    标签: java json spring api


    【解决方案1】:

    这是因为 subResult1 对象的类型为 Map,并且在每个循环中都会覆盖值,因为键(相同)被覆盖。由于sub1_arr 的所有元素都指向同一个对象,它们都会向您显示相同的结果

    相反,您可能想尝试类似的方法(获得 json 输出的更好方法 - 不要重新发明轮子):

    import com.fasterxml.jackson.databind.JsonNode;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.node.ArrayNode;
    import com.fasterxml.jackson.databind.node.ObjectNode;
    
    ObjectMapper mapper = new ObjectMapper();
    JsonNode rootNode = mapper.createObjectNode();
    ArrayNode arrayNode = mapper.createArrayNode();
    
    while(rs.next()) {
        ObjectNode layer = mapper.createObjectNode();   
        layer.put("layer2_id", rs.getString("layer2_id"));
        layer.put("layer2_name", rs.getString("layer2_name"));
        arrayNode.add(layer);
    }
    
    ((ObjectNode) rootNode).set("layer2", arrayNode);
    String jsonString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(rootNode);
    System.out.println(jsonString);
    

    这是我的测试:

    package com.example;
    
    import java.util.Arrays;
    
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.JsonNode;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.node.ArrayNode;
    import com.fasterxml.jackson.databind.node.ObjectNode;
    
    public class Main {
    
        public static void main(String[] args) throws JsonProcessingException {
            ObjectMapper mapper = new ObjectMapper();
            JsonNode rootNode = mapper.createObjectNode();
    
            ObjectNode layer1 = mapper.createObjectNode();
            layer1.put("layer2_id", "1");
            layer1.put("layer2_name", "name_1");
    
            ObjectNode layer2 = mapper.createObjectNode();
            layer2.put("layer2_id2", "2");
            layer2.put("layer2_name2", "name_2");
    
            ObjectNode layer3 = mapper.createObjectNode();
            layer3.put("layer2_id2", "3");
            layer3.put("layer2_name2", "name_3");
    
            ArrayNode arrayNode = mapper.createArrayNode();
            arrayNode.addAll(Arrays.asList(layer1, layer2, layer3));
    
            ((ObjectNode) rootNode).set("layer2", arrayNode);
    
            String jsonString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(rootNode);
            System.out.println(jsonString);
        }
    }
    

    输出:
    {"layer2":[
    {“layer2_id”:“1”,“layer2_name”:“name_1”},
    {"layer2_id" : "2", "layer2_name" : "name_2"},
    {“layer2_id”:“3”,“layer2_name”:“name_3”}
    ]}

    【讨论】:

      【解决方案2】:

      这是新开发人员的常见问题,当我担任编程导师时,这是人们弄清楚如何使用循环和数组后最常见的问题之一。问题在于 subresult1 实际上是对对象的引用。当您使用sub1_arr.add(subResult1) 这一行时,它在内存中始终是相同的引用,因此当您进行最后一次迭代时,所有值都相同,因为您一直在更新内存中的同一个对象。解决此问题的方法是将new 添加到 subResult1 对象。我不知道你有什么类型的对象,因为它没有包含在示例中,但是假设上面你有这个:

      Map<String, String> subResult1 = new HashMap<String, String>();
      

      在您的代码中,您需要添加以下内容:

      //subResult - layer2 subResult1 = new HashMap();

      这实际上是覆盖对原始 Map 的内存引用,并使用对新 Map 的引用创建一个新的。现在,旧地图仍然存在,因为您已将其添加到 sub1_arr。但是,当您使用“put”分配值时,它会将它们分配给您的新对象。

      有很多方法可以改进这一点,但首先,通常我喜欢将变量声明为尽可能接近我需要它们的点(不会造成太多混乱)。因此,我会将您对 subresult1 的声明移到同一个地方,并在循环上方将其消除。像这样:

      //subResult - layer2
      Map<String, String> subResult1 = new HashMap<String, String>();
      

      希望这会有所帮助!

      【讨论】:

        猜你喜欢
        • 2020-12-01
        • 1970-01-01
        • 2016-04-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多