且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何使用Jackson在Java中高效读取JSON文件中的数据?

更新时间:2023-01-16 08:14:41

在这种情况下创建 POJO 类是一种浪费,因为我们没有使用整个结果 List 但只有一个内部属性.为了避免这种情况,我们可以使用原生的 JsonNodeArrayNode 数据类型.我们可以使用 readTree 方法读取 JSON,遍历数组,找到给定的对象,最后转换内部的 code 数组.它可能如下所示:

import com.fasterxml.jackson.databind.JsonNode;导入 com.fasterxml.jackson.databind.ObjectMapper;导入 com.fasterxml.jackson.databind.node.ArrayNode;导入 java.io.File;导入 java.util.ArrayList;导入 java.util.Iterator;导入 java.util.List;公共类 JsonApp {public static void main(String[] args) 抛出异常 {File jsonFile = new File("./resource/test.json").getAbsoluteFile();ObjectMapper mapper = new ObjectMapper();ArrayNode rootArray = (ArrayNode) mapper.readTree(jsonFile);int size = rootArray.size();for (int i = 0; i < size; i++) {JsonNode jsonNode = rootArray.get(i);if (jsonNode.get("color").asText().equals("Blue")) {迭代器代码迭代器 = jsonNode.get("code").elements();列表代码 = 新的 ArrayList();代码迭代器.forEachRemaining(n -> 代码.add(n.asText()));System.out.println(codes);休息;}}}}

以上代码打印:

[012, 0324, 15478, 7412]

这个解决方案的缺点是我们将整个 JSON 加载到内存中,这对我们来说可能是一个问题.让我们尝试使用 Streaming API 来做到这一点.它使用起来有点困难,你必须知道你的 JSON 有效载荷是如何构造的,但它是使用 Jackson 获取 code 数组的最快方法.下面的实现是幼稚的,不能处理所有的可能性,所以你不应该依赖它:

import com.fasterxml.jackson.core.JsonFactory;导入 com.fasterxml.jackson.core.JsonParser;导入 com.fasterxml.jackson.core.JsonToken;导入 java.io.File;导入 java.io.IOException;导入 java.util.ArrayList;导入 java.util.Collections;导入 java.util.List;公共类 JsonApp {public static void main(String[] args) 抛出异常 {File jsonFile = new File("./resource/test.json").getAbsoluteFile();System.out.println(getBlueCodes(jsonFile));}私有静态列表getBlueCodes(File jsonFile) 抛出 IOException {尝试 (JsonParser 解析器 = new JsonFactory().createParser(jsonFile)) {while (parser.nextToken() != JsonToken.END_OBJECT) {String fieldName = parser.getCurrentName();//查找颜色属性if ("color".equals(fieldName)) {parser.nextToken();//找到蓝色if (parser.getText().equals("Blue")) {//跳过所有内容直到数组开始while (parser.nextToken() != JsonToken.START_ARRAY) ;列表代码 = 新的 ArrayList();while (parser.nextToken() != JsonToken.END_ARRAY) {代码.add(parser.getText());}返回代码;} 别的 {//跳过当前对象,因为它不是 `Blue`while (parser.nextToken() != JsonToken.END_OBJECT) ;}}}}返回 Collections.emptyList();}}

以上代码打印:

[012, 0324, 15478, 7412]

最后我需要提一下JsonPath 解决方案如果您可以使用其他库,这也很好:

import com.jayway.jsonpath.JsonPath;导入 net.minidev.json.JSONArray;导入 java.io.File;导入 java.util.List;导入 java.util.stream.Collectors;公共类 JsonPathApp {public static void main(String[] args) 抛出异常 {File jsonFile = new File("./resource/test.json").getAbsoluteFile();JSONArray 数组 = JsonPath.read(jsonFile, "$[?(@.color == 'Blue')].code");JSONArray jsonCodes = (JSONArray)array.get(0);列表代码 = jsonCodes.stream().map(Object::toString).collect(Collectors.toList());System.out.println(codes);}}

以上代码打印:

[012, 0324, 15478, 7412]

I store all static data in the JSON file. This JSON file has up to 1000 rows. How to get the desired data without storing all rows as ArrayList?

My code, I'm using right now and I want to increase its efficiency.

List<Colors> colorsList = new ObjectMapper().readValue(resource.getFile(), new TypeReference<Colors>() {});
    for(int i=0; i<colorsList.size(); i++){
        if(colorsList.get(i).getColor.equals("Blue")){
            return colorsList.get(i).getCode();
        }
    }

Is it possible? My goal is to increase efficiency without using ArrayList. Is there a way to make the code like this?

Colors colors = new ObjectMapper().readValue(..."Blue"...);  
return colors.getCode();

Resource.json

[
...
  {
    "color":"Blue",
    "code":["012","0324","15478","7412"]
  },
  {
    "color":"Red",
    "code":["145","001","1","7879","123984","89"]
  },
  {
    "color":"White",
    "code":["7","11","89","404"]
  }
...
]

Colors.java

class Colors {

    private String color;
    private List<String> code;

    public Colors() {
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public List<String> getCode() {
        return code;
    }

    public void setCode(List<String> code) {
        this.code = code;
    }

    @Override
    public String toString() {
        return "Colors{" +
                "color='" + color + '\'' +
                ", code=" + code +
                '}';
    }
}

Creating POJO classes in this case is a wasting because we do not use the whole result List<Colors> but only one internal property. To avoid this we can use native JsonNode and ArrayNode data types. We can read JSON using readTree method, iterate over array, find given object and finally convert internal code array. It could look like below:

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;

import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class JsonApp {

    public static void main(String[] args) throws Exception {
        File jsonFile = new File("./resource/test.json").getAbsoluteFile();

        ObjectMapper mapper = new ObjectMapper();

        ArrayNode rootArray = (ArrayNode) mapper.readTree(jsonFile);
        int size = rootArray.size();

        for (int i = 0; i < size; i++) {
            JsonNode jsonNode = rootArray.get(i);
            if (jsonNode.get("color").asText().equals("Blue")) {
                Iterator<JsonNode> codesIterator = jsonNode.get("code").elements();
                List<String> codes = new ArrayList<>();
                codesIterator.forEachRemaining(n -> codes.add(n.asText()));

                System.out.println(codes);
                break;
            }
        }
    }
}

Above code prints:

[012, 0324, 15478, 7412]

Downside of this solution is we load the whole JSON to memory which could be a problem for us. Let's try to use Streaming API to do that. It is a bit difficult to use and you must know how your JSON payload is constructed but it is the fastest way to get code array using Jackson. Below implementation is naive and does not handle all possibilities so you should not rely on it:

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class JsonApp {

    public static void main(String[] args) throws Exception {
        File jsonFile = new File("./resource/test.json").getAbsoluteFile();

        System.out.println(getBlueCodes(jsonFile));
    }

    private static List<String> getBlueCodes(File jsonFile) throws IOException {
        try (JsonParser parser = new JsonFactory().createParser(jsonFile)) {
            while (parser.nextToken() != JsonToken.END_OBJECT) {
                String fieldName = parser.getCurrentName();
                // Find color property
                if ("color".equals(fieldName)) {
                    parser.nextToken();
                    // Find Blue color
                    if (parser.getText().equals("Blue")) {
                        // skip everything until start of the array
                        while (parser.nextToken() != JsonToken.START_ARRAY) ;

                        List<String> codes = new ArrayList<>();
                        while (parser.nextToken() != JsonToken.END_ARRAY) {
                            codes.add(parser.getText());
                        }
                        return codes;
                    } else {
                        // skip current object because it is not `Blue`
                        while (parser.nextToken() != JsonToken.END_OBJECT) ;
                    }
                }
            }
        }

        return Collections.emptyList();
    }
}

Above code prints:

[012, 0324, 15478, 7412]

At the end I need to mention about JsonPath solution which also can be good if you can use other library:

import com.jayway.jsonpath.JsonPath;
import net.minidev.json.JSONArray;

import java.io.File;
import java.util.List;
import java.util.stream.Collectors;

public class JsonPathApp {
    public static void main(String[] args) throws Exception {
        File jsonFile = new File("./resource/test.json").getAbsoluteFile();

        JSONArray array = JsonPath.read(jsonFile, "$[?(@.color == 'Blue')].code");
        JSONArray jsonCodes = (JSONArray)array.get(0);
        List<String> codes = jsonCodes.stream()
                .map(Object::toString).collect(Collectors.toList());

        System.out.println(codes);
    }
}

Above code prints:

[012, 0324, 15478, 7412]