Why a Simple Log Caused FastJSON NPE: Inside JavaBeanSerializer Mechanics

The article recounts a production incident where adding a single log line caused a FastJSON NullPointerException, then reconstructs the scenario, analyzes the JavaBeanSerializer source code, presents serialization flowcharts, demonstrates example code with various @JSONField and @JSONType cases, and proposes coding standards to avoid similar serialization pitfalls.

dbaplus Community
dbaplus Community
dbaplus Community
Why a Simple Log Caused FastJSON NPE: Inside JavaBeanSerializer Mechanics

Incident Overview

A colleague added a single log statement to a newly introduced feature and, after deployment, the service generated a flood of alerts. Rolling back the change removed the log line and restored normal operation. The root cause was a NullPointerException (NPE) triggered during FastJSON serialization.

Reproducing the Issue

The problematic code defines a CountryDTO class and a test that serializes an empty instance with FastJSON.

public class CountryDTO {
    private String country;

    public void setCountry(String country) {
        this.country = country;
    }

    public String getCountry() {
        return this.country;
    }

    public Boolean isChinaName() {
        return this.country.equals("中国");
    }
}
public class FastJonTest {
    @Test
    public void testSerialize() {
        CountryDTO countryDTO = new CountryDTO();
        String str = JSON.toJSONString(countryDTO);
        System.out.println(str);
    }
}

Running the test throws an NPE because isChinaName() is invoked while country is still null.

NullPointerException screenshot
NullPointerException screenshot

Why Serialization Calls isChinaName()

FastJSON generates a serializer class (e.g., ASMSerializer_1_CountryDTO) using ASM bytecode manipulation. The generated write() method iterates over all getter‑style methods, including those that start with is, which explains why isChinaName() is executed during serialization.

Call chain stack trace
Call chain stack trace

JavaBeanSerializer Internals

The core of FastJSON serialization resides in JavaBeanSerializer. Its write() method delegates to computeGetters to collect methods that should be serialized.

public static List<FieldInfo> computeGetters(Class<?> clazz, /*...*/ ) {
    // omitted parts
    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) {
                // ...
            }
        }
        if (methodName.startsWith("get")) {
            // ...
        }
        if (methodName.startsWith("is")) {
            // ...
        }
    }
}

The selection follows three rules:

@JSONField(serialize = false, name = "xxx") disables serialization for the annotated method.

Methods prefixed with get are treated as property getters.

Methods prefixed with is are also treated as getters (typically for boolean‑like properties).

Serialization Flowchart

Serialization flowchart
Serialization flowchart

Example Cases and Recommended Annotations

The following class illustrates four typical situations and shows how @JSONField(serialize = false) can be used to exclude unwanted members from serialization.

@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() executed!!");
    }

    public Boolean isChinaName() {
        System.out.println("isChinaName() executed!!");
        return true;
    }

    public String getEnglishName() {
        System.out.println("getEnglishName() executed!!");
        return "lucy";
    }

    public String getOtherName() {
        System.out.println("getOtherName() executed!!");
        return "lucy";
    }

    @JSONField(serialize = false)
    public String getEnglishName2() {
        System.out.println("getEnglishName2() executed!!");
        return "lucy";
    }

    @JSONField(serialize = false)
    public void getEnglishName3() {
        System.out.println("getEnglishName3() executed!!");
    }

    @JSONField(serialize = false)
    public String isChinaName2() {
        System.out.println("isChinaName2() executed!!");
        return "isChinaName2";
    }
}

Serializing an empty instance yields:

isChinaName() executed!!
getEnglishName() executed!!
{"chinaName":true,"englishName":"lucy"}

Coding Guidelines

To prevent accidental inclusion of methods in JSON output, the article recommends explicitly annotating such methods with @JSONField(serialize = false). This makes the serialization intent obvious and reduces variance among team members.

High‑Frequency Serialization Scenarios

Three common patterns that frequently cause serialization problems are summarized in the diagram below.

High frequency serialization cases
High frequency serialization cases

Takeaways

The overall workflow is: detect the issue → analyze the root cause → apply a fix → codify the solution as a coding standard. The author also expresses a desire to decouple the project from FastJSON, allowing the JSON library to be swapped without code changes, and to limit excessive logging that can fill disks quickly.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

coding standardsfastjsonNPEJava serializationJSONFieldJavaBeanSerializer
dbaplus Community
Written by

dbaplus Community

Enterprise-level professional community for Database, BigData, and AIOps. Daily original articles, weekly online tech talks, monthly offline salons, and quarterly XCOPS&DAMS conferences—delivered by industry experts.

0 followers
Reader feedback

How this landed with the community

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.