Java序列化中如何让UserNo同时支持字符串与列表类型
问题描述
需要用Java的Rest Assured发送如下JSON请求:
{ "Document1": [ { "UserName": " ABC", "UserNo": "1234" }, { "UserName": " DEF", "UserNo": [ "2345", "4567" ] }, { "UserName": " MNO", "UserNo": "1234" } ] }
已创建对应的实体类Document1:
public class Document1{ private String UserName; private String UserNo public String getUserName(){ return UserName; } @JsonProperty("UserName") public void setUserName(String userName){ UserName = userName; } public String getUserNo(){ return UserNo; } @JsonProperty("UserNo") public void setUserNo(String userNo){ UserNo = userNo; } }
其中UserNo字段既可能是字符串类型,也可能是字符串列表类型。如果把UserNo改为List<String>类型:
private List<String> UserNo; public List<String> getUserNo(){ return UserNo; } @JsonProperty("UserNo") public void setUserNo(List<String> userNo){ UserNo = userNo; }
则仅能兼容UserName为DEF的情况,ABC的情况会序列化失败。
发送请求的addUser类代码如下:
public class addUser{ CreateUser cu = new CreateUser(); List<Document1> dc1 = new ArrayList(); Document1 d1 = new Document1(); d1.setUserName("ABC"); d1.setUserNo("1234"); dc1.add(d1); Document1 d2 = new Document1(); d2.setUserName("DEF"); d2.setUserNo("2345"); dc1.add(d2); }
请问如何实现UserNo字段在序列化时同时支持字符串和列表类型?
解决方案
要让UserNo同时兼容字符串和列表的序列化/反序列化,推荐用Jackson自定义序列化器的方式,既保证类型安全,又能灵活处理不同格式:
方法1:自定义序列化器与反序列化器
- 将
Document1中的UserNo统一改为List<String>类型,通过自定义逻辑处理序列化和反序列化的格式转换。 - 实现自定义序列化器:
public class UserNoSerializer extends JsonSerializer<List<String>> { @Override public void serialize(List<String> userNos, JsonGenerator gen, SerializerProvider serializers) throws IOException { if (userNos != null && userNos.size() == 1) { // 单个元素时输出为字符串 gen.writeString(userNos.get(0)); } else { // 多个元素或空时输出为数组 gen.writeObject(userNos); } } }
- 实现自定义反序列化器:
public class UserNoDeserializer extends JsonDeserializer<List<String>> { @Override public List<String> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { JsonNode node = p.getCodec().readTree(p); List<String> userNos = new ArrayList<>(); if (node.isTextual()) { // 字符串类型转为单个元素的列表 userNos.add(node.asText()); } else if (node.isArray()) { // 数组类型遍历添加到列表 for (JsonNode item : node) { userNos.add(item.asText()); } } return userNos; } }
- 修改
Document1类,给UserNo字段添加注解,并新增便捷方法:
public class Document1{ private String UserName; @JsonSerialize(using = UserNoSerializer.class) @JsonDeserialize(using = UserNoDeserializer.class) private List<String> UserNo; public String getUserName(){ return UserName; } @JsonProperty("UserName") public void setUserName(String userName){ UserName = userName; } public List<String> getUserNo(){ return UserNo; } @JsonProperty("UserNo") public void setUserNo(List<String> userNo){ UserNo = userNo; } // 新增便捷方法,直接传入单个字符串 public void setUserNo(String userNo){ this.UserNo = Collections.singletonList(userNo); } }
- 调整
addUser类的代码适配新逻辑:
import java.util.Arrays; public class addUser{ CreateUser cu = new CreateUser(); List<Document1> dc1 = new ArrayList(); Document1 d1 = new Document1(); d1.setUserName("ABC"); d1.setUserNo("1234"); dc1.add(d1); Document1 d2 = new Document1(); d2.setUserName("DEF"); d2.setUserNo(Arrays.asList("2345", "4567")); dc1.add(d2); Document1 d3 = new Document1(); d3.setUserName("MNO"); d3.setUserNo("1234"); dc1.add(d3); }
方法2:简易Object类型实现(非类型安全)
如果不想编写自定义序列化器,也可以将UserNo定义为Object类型,Jackson会自动根据实际类型输出对应格式,但这种方式缺乏类型校验:
public class Document1{ private String UserName; private Object UserNo; public String getUserName(){ return UserName; } @JsonProperty("UserName") public void setUserName(String userName){ UserName = userName; } public Object getUserNo(){ return UserNo; } @JsonProperty("UserNo") public void setUserNo(Object userNo){ UserNo = userNo; } // 便捷方法 public void setUserNo(String userNo){ this.UserNo = userNo; } public void setUserNo(List<String> userNo){ this.UserNo = userNo; } }
内容的提问来源于stack exchange,提问作者mohammed azharuddin
相关产品推荐
相关产品推荐

