Why FastJSON Calls isChinaName() During Serialization and How to Fix It

An unexpected NullPointerException occurs when adding a simple log line to a Java DTO, revealing that FastJSON’s serialization process invokes methods like isChinaName(), getXxx(), and isXxx() via ASM-generated serializers, and the article explains the underlying mechanism, common pitfalls, and best‑practice annotations to avoid such bugs.

Code Ape Tech Column
Code Ape Tech Column
Code Ape Tech Column
Why FastJSON Calls isChinaName() During Serialization and How to Fix It

Recently a very simple feature was added: a log line was inserted before the nightly release. After deployment a flood of alerts appeared, the code was rolled back, and the added log line was removed. The root cause was a NullPointerException triggered during serialization.

Reproducing the Issue

A CountryDTO class was defined:

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("中国"); }
}

A test class FastJonTest serializes an instance of CountryDTO using FastJSON:

public class FastJonTest {
    @Test
    public void testSerialize() {
        CountryDTO countryDTO = new CountryDTO();
        String str = JSON.toJSONString(countryDTO);
        System.out.println(str);
    }
}

The runtime error shows a NullPointerException at isChinaName(). The problem is that during serialization FastJSON calls isChinaName() while this.country is still null.

Why Does Serialization Invoke isChinaName()?

FastJSON uses ASM to generate a serializer class (e.g., ASMSerializer_1_CountryDTO) at runtime. The generated write method delegates to JavaBeanSerializer, which obtains an ObjectWriter via getObjectWriter(). Inside getObjectWriter(), FastJSON calls SerializeConfig#createJavaBeanSerializer and ultimately TypeUtils#computeGetters to collect getter methods.

The computeGetters logic scans all public methods of the class and includes:

Methods annotated with @JSONField(serialize = false, name = "xxx") (excluded from serialization).

Methods starting with get (standard getters).

Methods starting with is (boolean getters).

Therefore isChinaName() is treated as a getter and is invoked during serialization, causing the NullPointerException when the underlying field is null.

Serialization Flowchart

Serialization Flowchart
Serialization Flowchart

Example Code Demonstrating Common Cases

/**
 * 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 Boolean isChinaName() { System.out.println("isChinaName() executed!!"); return true; }
    public String getEnglishName() { System.out.println("getEnglishName() executed!!"); return "lucy"; }
    @JSONField(serialize = false)
    public static void queryCountryList() { System.out.println("queryCountryList() executed!!"); }
    @JSONField(serialize = false)
    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"; }
}

Running the test produces:

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

Best Practice for Controlling Serialization

To avoid accidental method invocation during serialization, explicitly exclude methods with @JSONField(serialize = false). This makes the serialization intent clear and prevents NullPointerExceptions caused by uninitialized fields.

By following this convention, developers can quickly identify which methods participate in serialization and maintain consistent code quality across the project.

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.

JavaserializationAnnotationsFastJSONASM
Code Ape Tech Column
Written by

Code Ape Tech Column

Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn

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.