import java.lang.reflect.*;
import java.util.*;
public class ReflectionJsonSerializer {
// 入口:List 序列化
public static String serializeList(List<?> list) {
if (list == null) return "[]";
StringBuilder sb = new StringBuilder("[");
String sep = "";
for (Object obj : list) {
sb.append(sep).append(serializeObject(obj));
sep = ",";
}
return sb.append("]").toString();
}
// 核心:單對象序列化
public static String serializeObject(Object obj) {
if (obj == null) return "null";
Class<?> clazz = obj.getClass();
StringBuilder sb = new StringBuilder("{");
String sep = "";
// 獲取所有聲明字段(含 private)
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
sb.append(sep);
sep = ",";
// 字段名
sb.append('"').append(field.getName()).append("\":");
// 讀取值:優先調用 getter,否則強制訪問字段
Object value = null;
try {
String getter = "get" + Character.toUpperCase(field.getName().charAt(0))
+ field.getName().substring(1);
Method method = clazz.getMethod(getter);
value = method.invoke(obj);
} catch (NoSuchMethodException e) {
// 無 getter,嘗試直接讀取字段
field.setAccessible(true);
try { value = field.get(obj); }
catch (IllegalAccessException ignored) {}
} catch (Exception ignored) {}
// 值序列化
appendValue(sb, value);
}
return sb.append("}").toString();
}
// 值類型分發
private static void appendValue(StringBuilder sb, Object value) {
if (value == null) {
sb.append("null");
} else if (value instanceof String) {
sb.append('"').append(escapeJson((String) value)).append('"');
} else if (value instanceof Number || value instanceof Boolean) {
sb.append(value.toString());
} else if (value instanceof Collection) {
sb.append(serializeList((List<?>) value)); // 簡化:僅處理 List
} else if (value.getClass().isArray()) {
sb.append(serializeArray(value));
} else {
// 嵌套對象遞歸
sb.append(serializeObject(value));
}
}
private static String serializeArray(Object array) {
int len = Array.getLength(array);
StringBuilder sb = new StringBuilder("[");
for (int i = 0; i < len; i++) {
if (i > 0) sb.append(",");
appendValue(sb, Array.get(array, i));
}
return sb.append("]").toString();
}
// 簡易 JSON 轉義
private static String escapeJson(String s) {
return s.replace("\\", "\\\\")
.replace("\"", "\\\"")
.replace("\n", "\\n")
.replace("\r", "\\r")
.replace("\t", "\\t");
}
}
public class User {
private String username;
private String sex;
private int age;
// getter/setter 省略
}
public static void main(String[] args) {
List<User> users = Arrays.asList(
new User("張三", "男", 25),
new User("李四", "女", 28)
);
String json = ReflectionJsonSerializer.serializeList(users);
System.out.println(json);
// 輸出: [{"username":"張三","sex":"男","age":25},{"username":"李四","sex":"女","age":28}]
}
| 缺口 | 增強方案 |
|---|---|
| 循環引用導致 StackOverflow | 引入 IdentityHashMap<Object, Boolean> visited 記錄已序列化對象 |
| 日期/時間類型無標準格式 | 檢測 java.time.* / Date,統一輸出 ISO-8601 |
| 字段命名策略固定 | 支援 @JsonProperty、蛇形命名、駝峰轉換配置 |
| 性能:反射每次解析 Method/Field | 緩存 Class -> Field[]/Method[] 元數據,或用 ASM 字節碼生成 |
| 無註解支援 (@JsonIgnore 等) | 解析字段/方法註解,動態跳過 |
| 輸出無格式化 | 加入 prettyPrint 參數,控制縮進換行 |
手寫反射 JSON 序列化器,核心在於 字段發現 → Getter/字段讀取 → 類型分發遞歸 → 字符串構建 四步。雖功能不及 Jackson/Gson 完備,但代碼量 < 100 行、零依賴、邏輯透明,是理解序列化原理、應對受限環境、實現定製化輸出的絕佳起點。生產環境請直接使用成熟庫,並在性能敏感處開啟 Afterburner (Jackson) 或預編譯 (Gson)。