Backend Development 9 min read

Understanding FastJson Serialization: Root Causes of NPE, Method Invocation Rules, and Best‑Practice Code Guidelines

This article reviews a production incident caused by a simple log statement, reconstructs the scenario with a CountryDTO example, analyzes FastJson's ASM‑based serializer internals, explains which getter/is methods are invoked during serialization, and proposes annotation‑driven coding standards to avoid similar bugs.

Java Architect Essentials
Java Architect Essentials
Java Architect Essentials
Understanding FastJson Serialization: Root Causes of NPE, Method Invocation Rules, and Best‑Practice Code Guidelines

Incident Review: A colleague added a single log line before releasing a simple feature; after deployment a flood of alerts appeared, leading to a rollback when the added log caused a NullPointerException during serialization.

Scenario Reconstruction: The problematic class CountryDTO and a test class FastJonTest are defined, illustrating how FastJson serializes the object and triggers the isChinaName() method when the country field is null.

Source Code Analysis: FastJson uses ASM to dynamically generate a serializer class ASMSerializer_1_CountryDTO . The core serialization work is performed by JavaBeanSerializer.write() , which obtains an object writer via getObjectWriter() and relies on SerializeConfig#createJavaBeanSerializer and TypeUtils#computeGetters to discover eligible methods.

public static List
computeGetters(Class
clazz, JSONType jsonType, Map
aliasMap, Map
fieldCacheMap, boolean sorted, PropertyNamingStrategy propertyNamingStrategy) {
    // ... omitted code ...
    Method[] methods = clazz.getMethods();
    for (Method method : methods) {
        if (method.getReturnType().equals(Void.TYPE)) continue;
        if (method.getParameterTypes().length != 0) continue;
        JSONField annotation = TypeUtils.getAnnotation(method, JSONField.class);
        if (annotation != null) {
            if (!annotation.serialize()) continue;
            if (annotation.name().length() != 0) {
                // ... omitted ...
            }
        }
        if (methodName.startsWith("get")) {
            // ... handle getter ...
        }
        if (methodName.startsWith("is")) {
            // ... handle boolean getter ...
        }
    }
}

Serialization Principle: The serializer invokes three kinds of methods – those annotated with @JSONField(serialize = false) are skipped, standard getters prefixed with get are used, and boolean getters prefixed with is are considered if they return a boolean.

Flowchart: A diagram (not reproduced here) visualizes the serialization steps from object inspection to JSON output.

Example Code: Demonstrates four typical cases – disabling serialization with @JSONField , void getters, non‑boolean is methods, and normal getters. The execution result shows which methods are actually called.

/**
 * case1: @JSONField(serialize = false)
 * case2: getXxx() returns void
 * case3: isXxx() returns non‑boolean
 * case4: @JSONType(ignores = "xxx")
 */
@JSONType(ignores = "otherName")
public class CountryDTO {
    private String country;
    public void setCountry(String country) { this.country = country; }
    public String getCountry() { return this.country; }
    public static void queryCountryList() { System.out.println("queryCountryList()执行!!"); }
    public Boolean isChinaName() { System.out.println("isChinaName()执行!!"); return true; }
    public String getEnglishName() { System.out.println("getEnglishName()执行!!"); return "lucy"; }
    @JSONField(serialize = false)
    public String getEnglishName2() { System.out.println("getEnglishName2()执行!!"); return "lucy"; }
    public void getEnglishName3() { System.out.println("getEnglishName3()执行!!"); }
    public String isChinaName2() { System.out.println("isChinaName2()执行!!"); return "isChinaName2"; }
}

Code Standards: To make serialization behavior explicit, it is recommended to annotate methods that should not participate with @JSONField(serialize = false) . This makes the codebase easier to audit and reduces accidental NPEs.

High‑Frequency Serialization Cases: A diagram (not reproduced) lists the three most common serialization scenarios observed in practice.

Conclusion: The article follows a pattern of problem discovery → principle analysis → solution → coding standards, emphasizing decoupling from a specific JSON library, minimizing unnecessary logging, and adopting clear annotation‑driven conventions.

backend developmentcode reviewJSONannotationsfastjsonJava Serialization
Java Architect Essentials
Written by

Java Architect Essentials

Committed to sharing quality articles and tutorials to help Java programmers progress from junior to mid-level to senior architect. We curate high-quality learning resources, interview questions, videos, and projects from across the internet to help you systematically improve your Java architecture skills. Follow and reply '1024' to get Java programming resources. Learn together, grow together.

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.