如何将继承自Java ArrayList的SkmeList类序列化为JSON?
嘿,这个问题我碰到过好多次——因为你的SkmeList继承了ArrayList,常规的JSON序列化库(比如Jackson、Gson)默认会把它当成纯数组来处理,直接忽略你自定义的skmeMajor、skmeMinor、skmeTable这些字段。下面给你两种主流库的解决方案,按需选就行:
方案1:用Jackson序列化(推荐如果项目用Spring的话)
Jackson默认会把集合类当成数组序列化,所以我们需要告诉它把SkmeList当成对象来处理,同时暴露集合里的元素:
方法A:通过注解调整序列化行为
给SkmeList类加上@JsonFormat(shape = JsonFormat.Shape.OBJECT)注解,再添加一个方法返回集合内的元素:
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonGetter; import java.util.ArrayList; @JsonFormat(shape = JsonFormat.Shape.OBJECT) public class SkmeList extends ArrayList<SkmeStatement> { private static final long serialVersionUID = 1L; private int skmeMajor = 0; private int skmeMinor = 0; private String skmeTable = null; // 你的现有getter/setter方法不变 @JsonGetter("statements") public ArrayList<SkmeStatement> getStatements() { return this; } }
这样序列化后,你会得到一个包含statements数组(存列表元素)和skmeMajor、skmeMinor、skmeTable字段的JSON对象。
方法B:优先用组合代替继承(更符合OOP原则)
如果可以修改类结构,别直接继承ArrayList,而是把它作为类的一个成员变量,这样序列化会自动包含所有字段,省心又规范:
import java.util.ArrayList; import java.util.List; public class SkmeList { private static final long serialVersionUID = 1L; private int skmeMajor = 0; private int skmeMinor = 0; private String skmeTable = null; // 用组合代替继承 private List<SkmeStatement> statements = new ArrayList<>(); // 添加操作集合的方法,比如: public boolean add(SkmeStatement stmt) { return statements.add(stmt); } // 你的现有getter/setter方法,加上statements的getter public List<SkmeStatement> getStatements() { return statements; } // 其他getter/setter... }
这种方式不需要额外配置,Jackson会直接把所有字段序列化出来。
方案2:用Gson序列化
Gson同样默认把继承集合的类当成数组,所以需要自定义一个序列化器:
步骤1:写自定义序列化器
import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonSerializer; import java.lang.reflect.Type; public class SkmeListSerializer implements JsonSerializer<SkmeList> { @Override public JsonElement serialize(SkmeList src, Type typeOfSrc, JsonSerializationContext context) { JsonObject jsonObj = new JsonObject(); // 序列化自定义字段 jsonObj.addProperty("skmeMajor", src.getSkmeMajor()); jsonObj.addProperty("skmeMinor", src.getSkmeMinor()); jsonObj.addProperty("skmeTable", src.getSkmeTable()); // 序列化集合里的元素 JsonArray stmtArray = new JsonArray(); for (SkmeStatement stmt : src) { stmtArray.add(context.serialize(stmt)); } jsonObj.add("statements", stmtArray); return jsonObj; } }
(注意:这里假设你给skmeMajor和skmeMinor补全了getter方法,如果没有的话,要么加getter,要么把字段改成public,或者用反射访问)
步骤2:注册序列化器并使用
import com.google.gson.Gson; import com.google.gson.GsonBuilder; public class Main { public static void main(String[] args) { SkmeList list = new SkmeList(); list.setTable("user_table"); list.setMajor(1); list.add(new SkmeStatement()); // 假设你有这个类的实例 // 注册自定义序列化器 Gson gson = new GsonBuilder() .registerTypeAdapter(SkmeList.class, new SkmeListSerializer()) .create(); // 转成JSON String json = gson.toJson(list); System.out.println(json); } }
最后提醒一句:如果SkmeStatement类本身有非public字段,也要确保JSON库能访问到——要么加getter,要么给字段加对应的注解(比如Jackson的@JsonProperty,Gson不需要额外配置只要字段不是private或者有getter)。
内容的提问来源于stack exchange,提问作者Nefarious

