Why Does FastJSON Invoke isChinaName() During Serialization? A Deep Dive

The article recounts a production incident caused by a simple log addition, then analyzes FastJSON’s serialization process, explaining why methods like isChinaName() are invoked, how ASM-generated serializers work, and offers best‑practice guidelines using @JSONField(serialize = false) to control serialization.

Programmer DD
Programmer DD
Programmer DD
Why Does FastJSON Invoke isChinaName() During Serialization? A Deep Dive

Online Incident Review

Earlier a very simple feature was added; before the evening release a log line was inserted to reflect the company's values. The line seemed harmless, but after deployment a flood of alerts appeared, prompting an immediate rollback and removal of the log code.

Scenario Reproduction

Define a CountryDTO class.
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("中国");
    }
}
Define a test class FastJonTest .
public class FastJonTest {
    @Test
    public void testSerialize() {
        CountryDTO countryDTO = new CountryDTO();
        String str = JSON.toJSONString(countryDTO);
        System.out.println(str);
    }
}

Running the test throws a NullPointerException because during serialization the method isChinaName() is executed while this.country is still null.

Why does serialization invoke isChinaName()?

What other methods are executed during serialization?

Source Code Analysis

Debugging reveals the call chain ending at ASMSerializer_1_CountryDTO.write, which is generated by FastJSON using ASM to avoid reflection overhead.

ASM technology can dynamically generate classes to replace Java reflection, reducing repeated reflection costs.

JavaBeanSerializer Serialization Principle

Serialization mainly calls JavaBeanSerializer.write(). JavaBeanSerializer obtains a writer via getObjectWriter(), which eventually calls

com.alibaba.fastjson.serializer.SerializeConfig#createJavaBeanSerializer

and com.alibaba.fastjson.util.TypeUtils#computeGetters.

public static List<FieldInfo> computeGetters(Class<?> clazz, JSONType jsonType, Map<String,String> aliasMap, Map<String,Field> 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 code ...
            }
        }
        if (methodName.startsWith("get")) {
            // ... omitted code ...
        }
        if (methodName.startsWith("is")) {
            // ... omitted code ...
        }
    }
}

The logic can be summarized into three cases: @JSONField(serialize = false, name = "xxx") annotation getXxx() getter methods isXxx() boolean getters

Serialization Flowchart

Example Code

/**
 * 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";
    }

    public String getOtherName() {
        System.out.println("getOtherName()执行!!");
        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";
    }
}

Running the above produces:

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

Code Standards

Serialization rules involve return types, parameter counts, and annotations such as @JSONType and @JSONField. Because team members have varying knowledge, it is advisable to explicitly mark non‑serializable methods with @JSONField(serialize = false) for clarity.

public class CountryDTO {
    private String country;

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

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

    @JSONField(serialize = false)
    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 getOtherName() {
        System.out.println("getOtherName()执行!!");
        return "lucy";
    }

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

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

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

Three Frequently Seen Serialization Cases

The overall process follows: discover the issue → analyze the principle → solve the problem → refine coding standards.

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.

JavaBackend DevelopmentserializationfastjsonASMJSONField
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

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.