Backend Development 13 min read

Performance Benchmark of Common Java JSON Libraries Using JMH

Using JMH, this article benchmarks the serialization and deserialization performance of four popular Java JSON libraries—Gson, Fastjson, Jackson, and Json-lib—by testing various scenarios with a complex Person model, analyzing results, and providing guidance on selecting the most suitable library for high‑performance applications.

Java Captain
Java Captain
Java Captain
Performance Benchmark of Common Java JSON Libraries Using JMH

This article uses JMH to benchmark the performance of several common Java JSON parsing libraries. While many online claims praise certain libraries, the author conducts hands‑on tests to provide reliable data.

JSON is a ubiquitous data‑exchange format in both web and server development. Performance concerns arise mainly in high‑throughput systems.

The four libraries evaluated are Gson, Fastjson, Jackson, and Json‑lib.

Brief introduction of each library

Gson – developed by Google, no external dependencies, provides toJson/fromJson.

Fastjson – Alibaba's high‑performance JSON processor, also dependency‑free, but has some issues with complex bean conversion.

Jackson – widely used, default JSON mapper in Spring MVC, modular architecture (core, annotations, databind).

Json‑lib – older library with many third‑party dependencies and limited support for complex types.

Maven dependencies

net.sf.json-lib
json-lib
2.4
jdk15
com.google.code.gson
gson
2.8.2
com.alibaba
fastjson
1.2.46
com.fasterxml.jackson.core
jackson-databind
2.9.4
com.fasterxml.jackson.core
jackson-annotations
2.9.4

Utility classes for each library

public class FastJsonUtil {
    public static String bean2Json(Object obj) {
        return JSON.toJSONString(obj);
    }
    public static
T json2Bean(String jsonStr, Class
objClass) {
        return JSON.parseObject(jsonStr, objClass);
    }
}
public class GsonUtil {
    private static Gson gson = new GsonBuilder().create();
    public static String bean2Json(Object obj) {
        return gson.toJson(obj);
    }
    public static
T json2Bean(String jsonStr, Class
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);
    }
}
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 json2Bean(String jsonStr, Class
objClass) {
        try {
            return mapper.readValue(jsonStr, objClass);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }
}
public class JsonLibUtil {
    public static String bean2Json(Object obj) {
        JSONObject jsonObject = JSONObject.fromObject(obj);
        return jsonObject.toString();
    }
    @SuppressWarnings("unchecked")
    public static
T json2Bean(String jsonStr, Class
objClass) {
        return (T) JSONObject.toBean(JSONObject.fromObject(jsonStr), objClass);
    }
}

Model classes used in the benchmark

public class Person {
    private String name;
    private FullName fullName;
    private int age;
    private Date birthday;
    private List
hobbies;
    private Map
clothes;
    private List
friends;
    // getters/setters omitted
    @Override
    public String toString() { /* ... */ }
}
public class FullName {
    private String firstName;
    private String middleName;
    private String lastName;
    // constructors, getters/setters, toString omitted
}

Serialization 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
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() { /* create Person instance with friends */ }
    @TearDown public void shutdown() {}
}

The results show that for a small number of serializations Gson is fastest, but as the count grows to 100 000 Fastjson overtakes Gson, while Jackson consistently performs well. Json‑lib is dramatically slower.

Deserialization 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
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\":\"...\"}"; }
    @TearDown public void shutdown() {}
}

Deserialization results indicate that Gson, Jackson and Fastjson have comparable performance and are all suitable for high‑throughput scenarios, whereas Json‑lib remains far behind.

Conclusion

The benchmark provides concrete data to help developers choose the most appropriate JSON library based on their specific performance requirements.

JavaPerformance BenchmarkJSONfastjsonGsonJacksonJMHJson-lib
Java Captain
Written by

Java Captain

Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.