如何将JSON反序列化为带嵌套泛型的Java对象?
完全可以解决这个问题!不管是用Gson还是Jackson,我们都能通过自定义反序列化逻辑,把JSON里的扁平值适配到你的嵌套包装类里。下面分别给你两种框架的实现方案:
Gson 解决方案
核心思路是为BaseModel<T>和BaseListModel<T>编写自定义反序列化器,让Gson知道如何把单个JSON值/数组转换成对应的包装类实例。
1. 编写BaseModel通用反序列化器
这个反序列化器会直接把JSON中的单个值包装成BaseModel对象:
public class BaseModelDeserializer<T> implements JsonDeserializer<BaseModel<T>> { private final Type valueType; public BaseModelDeserializer(Type valueType) { this.valueType = valueType; } @Override public BaseModel<T> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { // 直接将JSON值反序列化为泛型类型,再包装进BaseModel T value = context.deserialize(json, valueType); return new BaseModel<>(value); } }
2. 编写BaseListModel通用反序列化器
针对数组类型的JSON值,我们需要把它转换成List<T>后再包装进BaseListModel:
public class BaseListModelDeserializer<T> implements JsonDeserializer<BaseListModel<T>> { private final Type elementType; public BaseListModelDeserializer(Type elementType) { this.elementType = elementType; } @Override public BaseListModel<T> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { // 先把JSON数组反序列化为List<T> List<T> valueList = context.deserialize(json, TypeToken.getParameterized(List.class, elementType).getType()); BaseListModel<T> model = new BaseListModel<>(); model.setValue(valueList); return model; } }
3. 配置Gson并完成反序列化
注意:JSON中的字段是"ID"(大写开头),而你的POJO字段是id(小写),需要在MyObject类的id字段上添加@SerializedName("ID")注解来匹配,或者在GsonBuilder中配置字段命名策略。
// 先修改MyObject类添加注解 public class MyObject { @SerializedName("ID") private BaseModel<Integer> id; private BaseModel<String> title; private BaseListModel<Integer> numbers; // 可添加getter/setter,Gson默认可访问私有字段 } // 主类中的反序列化代码 public class Main { public static void main(String[] args) { String json = "[{\"ID\":1,\"title\":\"title1\",\"numbers\":[1,2]},{\"ID\":2,\"title\":\"title2\",\"numbers\":[10,20]}]"; Gson gson = new GsonBuilder() // 注册BaseModel<Integer>的反序列化器(对应id字段) .registerTypeAdapter(TypeToken.getParameterized(BaseModel.class, Integer.class).getType(), new BaseModelDeserializer<>(Integer.class)) // 注册BaseModel<String>的反序列化器(对应title字段) .registerTypeAdapter(TypeToken.getParameterized(BaseModel.class, String.class).getType(), new BaseModelDeserializer<>(String.class)) // 注册BaseListModel<Integer>的反序列化器(对应numbers字段) .registerTypeAdapter(TypeToken.getParameterized(BaseListModel.class, Integer.class).getType(), new BaseListModelDeserializer<>(Integer.class)) .create(); List<MyObject> myObjects = gson.fromJson(json, new TypeToken<List<MyObject>>(){}.getType()); // 测试输出验证结果 for (MyObject obj : myObjects) { System.out.println("ID: " + obj.id.getValue()); System.out.println("Title: " + obj.title.getValue()); System.out.println("Numbers: " + obj.numbers.getValue()); } } }
Jackson 解决方案
Jackson同样可以通过自定义反序列化器实现需求,步骤和Gson类似:
1. 编写BaseModel反序列化器
public class BaseModelDeserializer<T> extends StdDeserializer<BaseModel<T>> { private final JavaType valueType; public BaseModelDeserializer(JavaType valueType) { super(BaseModel.class); this.valueType = valueType; } @Override public BaseModel<T> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { T value = ctxt.readValue(p, valueType); return new BaseModel<>(value); } }
2. 编写BaseListModel反序列化器
public class BaseListModelDeserializer<T> extends StdDeserializer<BaseListModel<T>> { private final JavaType listType; public BaseListModelDeserializer(JavaType elementType, DeserializationContext ctxt) { super(BaseListModel.class); this.listType = ctxt.getTypeFactory().constructCollectionType(List.class, elementType); } @Override public BaseListModel<T> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { List<T> list = ctxt.readValue(p, listType); BaseListModel<T> model = new BaseListModel<>(); model.setValue(list); return model; } }
3. 配置ObjectMapper并反序列化
Jackson可以通过配置开启大小写不敏感匹配,来处理"ID"和id的字段名差异:
public class Main { public static void main(String[] args) throws IOException { String json = "[{\"ID\":1,\"title\":\"title1\",\"numbers\":[1,2]},{\"ID\":2,\"title\":\"title2\",\"numbers\":[10,20]}]"; ObjectMapper mapper = new ObjectMapper(); SimpleModule module = new SimpleModule(); TypeFactory typeFactory = mapper.getTypeFactory(); // 注册各泛型类型的反序列化器 module.addDeserializer(typeFactory.constructParametricType(BaseModel.class, Integer.class), new BaseModelDeserializer<>(typeFactory.constructType(Integer.class))); module.addDeserializer(typeFactory.constructParametricType(BaseModel.class, String.class), new BaseModelDeserializer<>(typeFactory.constructType(String.class))); module.addDeserializer(typeFactory.constructParametricType(BaseListModel.class, Integer.class), new BaseListModelDeserializer<>(typeFactory.constructType(Integer.class), mapper.getDeserializationContext())); mapper.registerModule(module); // 开启字段名大小写不敏感匹配,解决JSON中"ID"和POJO中"id"的差异 mapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true); List<MyObject> myObjects = mapper.readValue(json, new TypeReference<List<MyObject>>(){}); // 测试输出验证结果 for (MyObject obj : myObjects) { System.out.println("ID: " + obj.id.getValue()); System.out.println("Title: " + obj.title.getValue()); System.out.println("Numbers: " + obj.numbers.getValue()); } } }
内容的提问来源于stack exchange,提问作者Russ Wheeler
相关产品推荐
相关产品推荐

