Comparing the performance of several commonly used JSON libraries in Java, which one is the strongest?

  • a brief introdction

    • Gson
    • FastJson
    • Jackson
    • Json-lib
    • Write performance tests
    • Add maven dependency
    • Tool classes of the four libraries
    • Prepare the Model class
    • JSON serialization performance benchmark
    • JSON Deserialization Performance Benchmark

This article uses JMH to test the performance of several common JSON parsing libraries in Java. Every time I see what other people say on the Internet about how good the performance of a certain library is, it crushes other libraries. But seeing is worth seeing, only what you have tested with your own hands is the most trustworthy.

JSON is a very common data transmission format in both web development and server development. In general, we don't need to care too much about the performance of JSON parsing and construction, unless it is a system with relatively high performance requirements.

At present, there are many open source JSON libraries for Java. Below we take four commonly used JSON libraries for performance testing and comparison, and analyze how to choose the most suitable JSON library according to the actual application scenario based on the test results.

The four JSON libraries are: Gson, FastJson, Jackson, Json-lib.

a brief introdction

Choosing a suitable JSON library should consider several aspects:

  • String parsing into JSON performance
  • String parsing into JavaBean performance
  • JavaBean construction JSON performance
  • Collection construction JSON performance
  • ease of use

First briefly introduce the identity background of the four class libraries

Gson

Project address: https://github.com/google/gson

Gson is currently the most complete Json parsing artifact. Gson was originally developed by Google in response to Google's internal needs, but it has been used by many companies or users since the first version was released publicly in May 2008. The application of Gson mainly consists of two conversion functions, toJson and fromJson. It has no dependencies, does not require additional jars, and can run directly on the JDK. Before using this object conversion, you need to create the object type and its members to successfully convert the JSON string into the corresponding object. As long as there are get and set methods in the class, Gson can fully realize the conversion of complex types of json to bean or bean to json, and is an artifact of JSON parsing.

FastJson

Project address: https://github.com/alibaba/fastjson

Fastjson is a high-performance JSON processor written in Java, developed by Alibaba. No dependencies, no need for extra jars, and can run directly on the JDK. FastJson will have some problems in converting Json of complex types of beans. There may be types of references, which will cause errors in Json conversion, and references need to be formulated. FastJson uses an original algorithm to increase the speed of parse to the extreme, surpassing all json libraries.

Jackson

Project address: https://github.com/FasterXML/jackson

Jackson is a widely used Java open source framework for serializing and deserializing json. The Jackson community is relatively active and the update speed is relatively fast. According to the statistics in Github, Jackson is one of the most popular json parsers, and the default json parser of Spring MVC is Jackson.

Jackson has many advantages:

  • Jackson relies on fewer jar packages and is easy to use.
  • Compared with other Java json frameworks such as Gson, Jackson parses large json files faster.
  • Jackson runs with relatively low memory usage and better performance
  • Jackson has a flexible API that can be easily extended and customized.

Currently the latest version is 2.9.4, Jackson's core module consists of three parts:

  1. The jackson-core core package provides related APIs based on "flow mode" parsing, including JsonPaser and JsonGenerator. The internal implementation of Jackson is to generate and parse json through the JsonGenerator and JsonParser of the high-performance streaming mode API.
  2. jackson-annotations annotation package, providing standard annotation functions;
  3. jackson-databind data binding package, providing related API ( ObjectMapper ) based on "object binding" analysis and related API (JsonNode) based on "tree model" analysis; API based on "object binding" analysis and "tree model" analysis APIs that rely on APIs that are parsed based on "stream mode".

Why is Jackson's introduction so long? Because it is also my favorite.

Json-lib

Project address: http://json-lib.sourceforge.net/index.html

The beginning of json-lib is also the most widely used json parsing tool. The disadvantage of json-lib is that it depends on many third-party packages. For the conversion of complex types, json-lib has defects in converting json into beans, such as A list or map collection of another class will appear in one class, and there will be problems in the conversion of json-lib from json to beans. json-lib cannot meet the needs of the Internet today in terms of function and performance.

Write performance tests

Next, start writing the performance test code of these four libraries.

Add maven dependency

Of course, the first thing is to add the maven dependencies of the four libraries. To be fair, I use the latest versions of them all:

<!-- Json libs-->
<dependency>
    <groupId>net.sf.json-lib</groupId>
    <artifactId>json-lib</artifactId>
    <version>2.4</version>
    <classifier>jdk15</classifier>
</dependency>
<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.2</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.46</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.4</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.9.4</version>
</dependency>

Tool classes of the four libraries

FastJsonUtil.java

public class FastJsonUtil {
    
    
    public static String bean2Json(Object obj) {
    
    
        return JSON.toJSONString(obj);
    }

    public static <T> T json2Bean(String jsonStr, Class<T> objClass) {
    
    
        return JSON.parseObject(jsonStr, objClass);
    }
}

GsonUtil.java

public class GsonUtil {
    
    
    private static Gson gson = new GsonBuilder().create();

    public static String bean2Json(Object obj) {
    
    
        return gson.toJson(obj);
    }

    public static <T> T json2Bean(String jsonStr, Class<T> objClass) {
    
    
        return gson.fromJson(jsonStr, objClass);
    }

    public static String jsonFormatter(String uglyJsonStr) {
    
    
        Gson gson = new GsonBuilder().setPrettyPrinting().create();
        JsonParser jp = new JsonParser();
        JsonElement je = jp.parse(uglyJsonStr);
        return gson.toJson(je);
    }
}

JacksonUtil.java

public class JacksonUtil {
    
    
    private static ObjectMapper mapper = new ObjectMapper();

    public static String bean2Json(Object obj) {
    
    
        try {
    
    
            return mapper.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
    
    
            e.printStackTrace();
            return null;
        }
    }

    public static <T> T json2Bean(String jsonStr, Class<T> objClass) {
    
    
        try {
    
    
            return mapper.readValue(jsonStr, objClass);
        } catch (IOException e) {
    
    
            e.printStackTrace();
            return null;
        }
    }
}

JsonLibUtil.java

public class JsonLibUtil {
    
    

    public static String bean2Json(Object obj) {
    
    
        JSONObject jsonObject = JSONObject.fromObject(obj);
        return jsonObject.toString();
    }

    @SuppressWarnings("unchecked")
    public static <T> T json2Bean(String jsonStr, Class<T> objClass) {
    
    
        return (T) JSONObject.toBean(JSONObject.fromObject(jsonStr), objClass);
    }
}

Prepare the Model class

Here I write a simple Person class, and at the same time, the attributes include Date, List, Map and a custom class FullName to simulate the real scene to the greatest extent.

public class Person {
    
    
    private String name;
    private FullName fullName;
    private int age;
    private Date birthday;
    private List<String> hobbies;
    private Map<String, String> clothes;
    private List<Person> friends;

    // getter/setter省略

    @Override
    public String toString() {
    
    
        StringBuilder str = new StringBuilder("Person [name=" + name + ", fullName=" + fullName + ", age="
                + age + ", birthday=" + birthday + ", hobbies=" + hobbies
                + ", clothes=" + clothes + "]\n");
        if (friends != null) {
    
    
            str.append("Friends:\n");
            for (Person f : friends) {
    
    
                str.append("\t").append(f);
            }
        }
        return str.toString();
    }

}
public class FullName {
    
    
    private String firstName;
    private String middleName;
    private String lastName;

    public FullName() {
    
    
    }

    public FullName(String firstName, String middleName, String lastName) {
    
    
        this.firstName = firstName;
        this.middleName = middleName;
        this.lastName = lastName;
    }

    // 省略getter和setter

    @Override
    public String toString() {
    
    
        return "[firstName=" + firstName + ", middleName="
                + middleName + ", lastName=" + lastName + "]";
    }
}

JSON serialization performance benchmark

@BenchmarkMode(Mode.SingleShotTime)
@OutputTimeUnit(TimeUnit.SECONDS)
@State(Scope.Benchmark)
public class JsonSerializeBenchmark {
    
    
    /**
     * 序列化次数参数
     */
    @Param({
    
    "1000", "10000", "100000"})
    private int count;

    private Person p;

    public static void main(String[] args) throws Exception {
    
    
        Options opt = new OptionsBuilder()
                .include(JsonSerializeBenchmark.class.getSimpleName())
                .forks(1)
                .warmupIterations(0)
                .build();
        Collection<RunResult> results =  new Runner(opt).run();
        ResultExporter.exportResult("JSON序列化性能", results, "count", "秒");
    }

    @Benchmark
    public void JsonLib() {
    
    
        for (int i = 0; i < count; i++) {
    
    
            JsonLibUtil.bean2Json(p);
        }
    }

    @Benchmark
    public void Gson() {
    
    
        for (int i = 0; i < count; i++) {
    
    
            GsonUtil.bean2Json(p);
        }
    }

    @Benchmark
    public void FastJson() {
    
    
        for (int i = 0; i < count; i++) {
    
    
            FastJsonUtil.bean2Json(p);
        }
    }

    @Benchmark
    public void Jackson() {
    
    
        for (int i = 0; i < count; i++) {
    
    
            JacksonUtil.bean2Json(p);
        }
    }

    @Setup
    public void prepare() {
    
    
        List<Person> friends=new ArrayList<Person>();
        friends.add(createAPerson("小明",null));
        friends.add(createAPerson("Tony",null));
        friends.add(createAPerson("陈小二",null));
        p=createAPerson("邵同学",friends);
    }

    @TearDown
    public void shutdown() {
    
    
    }

    private Person createAPerson(String name,List<Person> friends) {
    
    
        Person newPerson=new Person();
        newPerson.setName(name);
        newPerson.setFullName(new FullName("zjj_first", "zjj_middle", "zjj_last"));
        newPerson.setAge(24);
        List<String> hobbies=new ArrayList<String>();
        hobbies.add("篮球");
        hobbies.add("游泳");
        hobbies.add("coding");
        newPerson.setHobbies(hobbies);
        Map<String,String> clothes=new HashMap<String, String>();
        clothes.put("coat", "Nike");
        clothes.put("trousers", "adidas");
        clothes.put("shoes", "安踏");
        newPerson.setClothes(clothes);
        newPerson.setFriends(friends);
        return newPerson;
    }
}

To illustrate, in the code above

ResultExporter.exportResult("JSON序列化性能", results, "count", "秒");

This is a method I wrote myself to fill the performance test report data into the Echarts graph, and then export the png image.

The result graph after execution:

insert image description here

From the above test results, it can be seen that Gson has the best performance when the number of serializations is relatively small. When the number of serializations increases continuously to 100,000, Gson details are weaker than Jackson and FastJson. At this time, the performance of FastJson is really good, and it can also be used. It can be seen that whether the number is small or large, Jackson has always performed well. And that Json-lib is just for fun. _

JSON Deserialization Performance Benchmark

@BenchmarkMode(Mode.SingleShotTime)
@OutputTimeUnit(TimeUnit.SECONDS)
@State(Scope.Benchmark)
public class JsonDeserializeBenchmark {
    
    
    /**
     * 反序列化次数参数
     */
    @Param({
    
    "1000", "10000", "100000"})
    private int count;

    private String jsonStr;

    public static void main(String[] args) throws Exception {
    
    
        Options opt = new OptionsBuilder()
                .include(JsonDeserializeBenchmark.class.getSimpleName())
                .forks(1)
                .warmupIterations(0)
                .build();
        Collection<RunResult> results =  new Runner(opt).run();
        ResultExporter.exportResult("JSON反序列化性能", results, "count", "秒");
    }

    @Benchmark
    public void JsonLib() {
    
    
        for (int i = 0; i < count; i++) {
    
    
            JsonLibUtil.json2Bean(jsonStr, Person.class);
        }
    }

    @Benchmark
    public void Gson() {
    
    
        for (int i = 0; i < count; i++) {
    
    
            GsonUtil.json2Bean(jsonStr, Person.class);
        }
    }

    @Benchmark
    public void FastJson() {
    
    
        for (int i = 0; i < count; i++) {
    
    
            FastJsonUtil.json2Bean(jsonStr, Person.class);
        }
    }

    @Benchmark
    public void Jackson() {
    
    
        for (int i = 0; i < count; i++) {
    
    
            JacksonUtil.json2Bean(jsonStr, Person.class);
        }
    }

    @Setup
    public void prepare() {
    
    
        jsonStr="{
    
    \"name\":\"邵同学\",\"fullName\":{
    
    \"firstName\":\"zjj_first\",\"middleName\":\"zjj_middle\",\"lastName\":\"zjj_last\"},\
        "age\":24,\"birthday\":null,\"hobbies\":[\"篮球\",\"游泳
        \",\"coding\"],\"clothes\":{
    
    \"shoes\":\"安踏\",\"trousers\":\"adidas\",\"coat\":\"Nike\"},\"friends\":[{
    
    \"name\":\"小明
        \",\"fullName\":{
    
    \"firstName\":\"xxx_first\",\"middleName\":\"xxx_middle\",\"lastName\":\"xxx_last\"},\
        "age\":24,\"birthday\":null,\"hobbies\":[\"篮球\",\"游泳
        \",\"coding\"],\"clothes\":{
    
    \"shoes\":\"安踏
        \",\"trousers\":\"adidas\",\"coat\":\"Nike\"},\"friends\":null},
        {
    
    \"name\":\"Tony\",\"fullName\":
        {
    
    \"firstName\":\"xxx_first\",\"middleName\":\"xxx_middle\",\"lastName\":\"xxx_last\"},\
        "age\":24,\"birthday\":null,\"hobbies\":[\"篮球\",\"游泳
        \",\"coding\"],\"clothes\":{
    
    \"shoes\":\"安踏
        \",\"trousers\":\"adidas\",\"coat\":\"Nike\"},\"friends\":null},{
    
    \"name\":\"陈
        小二\",\"fullName\":
        {
    
    \"firstName\":\"xxx_first\",\"middleName\":\"xxx_middle\",\"lastName\":\"xxx_last\"},\
        "age\":24,\"birthday\":null,\"hobbies\":[\"篮球\",\"游泳
        \",\"coding\"],\"clothes\":{
    
    \"shoes\":\"安踏
        \",\"trousers\":\"adidas\",\"coat\":\"Nike\"},\"friends\":null}]}";
       
    }

    @TearDown
    public void shutdown() {
    
    
    }
}

The result graph after execution:

insert image description here

From the above test results, we can see that when deserializing, there is not much difference between Gson, Jackson and FastJson, and the performance is very good, but the Json-lib is still here to continue to be funny.

Guess you like

Origin blog.csdn.net/qq_43842093/article/details/131745718