Understanding FastJSON Serialization: Why isChinaName() Is Invoked and How to Control Serialized Methods
This article analyzes a FastJSON serialization issue where a getter method is unexpectedly called, explains the underlying ASM‑generated serializer mechanism, details which methods FastJSON invokes during serialization, and proposes using @JSONField(serialize = false) to explicitly exclude methods from the serialization process.
Incident Review
Recently a simple logging line was added to a new feature, but after deployment a cascade of alerts forced a rollback. The root cause was a NullPointerException triggered during JSON serialization.
Reproducing the Problem
Define a CountryDTO class and a test class FastJonTest that serializes an instance using 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 a NullPointerException because isChinaName() is invoked while country is still null.
Why isChinaName() Is Executed?
FastJSON uses ASM to generate a serializer class (e.g., ASMSerializer_1_CountryDTO) that replaces reflection. The generated write() method calls JavaBeanSerializer.write(), which obtains an ObjectWriter that inspects getter methods.
During the inspection FastJSON’s computeGetters method treats any public method with no parameters and a non‑void return type that starts with get or is as a property accessor, unless it is excluded by annotations.
public static List<FieldInfo> computeGetters(Class<?> clazz, JSONType jsonType, ... ) {
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 && !annotation.serialize()) continue;
if (methodName.startsWith("get")) { /* handle getter */ }
if (methodName.startsWith("is")) { /* handle boolean getter */ }
}
}Thus isChinaName() is considered a boolean getter and is called during serialization, leading to the NPE.
What Methods Are Invoked During Serialization?
@JSONField(serialize = false, name = "xxx") – excluded.
Methods starting with get – treated as getters.
Methods starting with is – treated as boolean getters.
Recommended Coding Practice
To avoid accidental invocation, explicitly mark methods that should not be serialized with @JSONField(serialize = false). The following example shows a clean version of CountryDTO where only intended properties are serialized:
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() executed!!"); }
public Boolean isChinaName() { System.out.println("isChinaName() executed!!"); return true; }
public String getEnglishName() { System.out.println("getEnglishName() executed!!"); return "lucy"; }
@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 now produces the expected JSON without NPE:
isChinaName() executed!!
getEnglishName() executed!!
{"chinaName":true,"englishName":"lucy"}Conclusion
The debugging process followed the pattern: discover the issue → analyze the underlying FastJSON serialization mechanism → apply a solution (explicit exclusion) → formalize a coding guideline. Understanding which methods FastJSON treats as properties helps prevent similar bugs in backend Java projects.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Architecture Digest
Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
