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
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.
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.