FastJSON Serialization Mechanics: Why isChinaName() Executes and How to Control Serialized Output
This article analyzes a FastJSON serialization issue where a newly added log line triggered unexpected method calls, explains the underlying ASM‑generated serializer and JavaBeanSerializer logic, demonstrates code examples, outlines common pitfalls such as @JSONField annotations and getter patterns, and proposes best‑practice conventions for reliable backend serialization.
Online incident review : A simple feature was added with an extra log statement before deployment; after going live, a flood of alerts forced an immediate rollback.
Scenario reconstruction : The CountryDTO class and a test class FastJonTest were defined. During serialization, a NullPointerException occurred because the method isChinaName() was invoked while the country field was still null.
Source code analysis : FastJSON uses ASM to dynamically generate a class named ASMSerializer_1_CountryDTO . The actual serialization is performed by JavaBeanSerializer.write() . The method com.alibaba.fastjson.util.TypeUtils.computeGetters determines which getters are included based on return type, parameters, and annotations.
public static List<FieldInfo> computeGetters(Class<?> clazz, JSONType jsonType, Map<String,String> aliasMap, Map<String,Field> fieldCacheMap, boolean sorted, PropertyNamingStrategy propertyNamingStrategy) {
// ...
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;
// handle name alias
}
String methodName = method.getName();
if (methodName.startsWith("get")) {
// treat as getter
}
if (methodName.startsWith("is")) {
// treat as boolean getter
}
}
}Three exclusion cases :
@JSONField(serialize = false, name = "xxx") annotation explicitly disables serialization.
Getter methods with a void return type are ignored.
Methods starting with is that do not return a boolean are ignored.
Serialization flow : The process follows the pattern – problem discovery → principle analysis → solution implementation → coding standards improvement.
Example code demonstrating the cases:
@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 String getEnglishName2() { System.out.println("getEnglishName2() executed!!"); return "lucy"; }
// other methods omitted for brevity
}Running result : The console prints isChinaName() executed!! and getEnglishName() executed!! , and the final JSON output is {"chinaName":true,"englishName":"lucy"} .
Code conventions : To avoid accidental serialization, it is recommended to annotate non‑serializable methods with @JSONField(serialize = false) , making the intent explicit and improving code readability.
Top Architect
Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.
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.