Java中多类型字段的JSON反序列化及POJO设计咨询
处理Java中多类型字段的JSON反序列化问题
首先明确你要处理的三种JSON结构:
变体1(仅字符串类型errorMessage):
{"errorMessage": "系统异常"}变体2(含errorType和字符串errorMessage):
{"errorType": "VALIDATION", "errorMessage": "参数格式错误"}变体3(含errorType和对象类型errorMessage):
{"errorType": "BUSINESS", "errorMessage": {"code": "BIZ-001", "message": "库存不足"}}
下面提供两种可行的解决方案,优先推荐第一种自定义反序列化器的方式,类型判断更清晰,代码可读性更强。
方案1:自定义反序列化器(推荐)
步骤1:定义基础数据类
首先定义对应变体3中errorMessage对象的实体类:
public class ErrorMessageDetail { private String code; private String message; // 必须有无参构造方法,Jackson反序列化需要 public ErrorMessageDetail() {} // Getter & Setter public String getCode() { return code; } public void setCode(String code) { this.code = code; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
然后定义一个包装类,用来统一封装字符串和对象两种类型的errorMessage:
public class ErrorMessageWrapper { private String simpleMessage; private ErrorMessageDetail detailMessage; // 针对字符串类型的构造方法 public ErrorMessageWrapper(String simpleMessage) { this.simpleMessage = simpleMessage; } // 针对对象类型的构造方法 public ErrorMessageWrapper(ErrorMessageDetail detailMessage) { this.detailMessage = detailMessage; } // 判断当前是哪种类型的消息 public boolean isSimpleMessage() { return simpleMessage != null; } // Getter方法 public String getSimpleMessage() { return simpleMessage; } public ErrorMessageDetail getDetailMessage() { return detailMessage; } }
步骤2:编写自定义反序列化器
创建一个反序列化器,根据JSON节点的类型,将errorMessage转换成对应的包装类实例:
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; public class ErrorMessageDeserializer extends JsonDeserializer<ErrorMessageWrapper> { @Override public ErrorMessageWrapper deserialize(JsonParser parser, DeserializationContext context) throws IOException { ObjectMapper mapper = (ObjectMapper) parser.getCodec(); JsonNode node = mapper.readTree(parser); if (node.isTextual()) { // 字符串类型,直接返回包装了字符串的实例 return new ErrorMessageWrapper(node.asText()); } else if (node.isObject()) { // 对象类型,转换成ErrorMessageDetail后再包装 ErrorMessageDetail detail = mapper.treeToValue(node, ErrorMessageDetail.class); return new ErrorMessageWrapper(detail); } return null; } }
步骤3:定义主响应类并关联反序列化器
在主响应类中,给errorMessage字段标记使用自定义反序列化器:
import com.fasterxml.jackson.databind.annotation.JsonDeserialize; public class ErrorResponse { private String errorType; @JsonDeserialize(using = ErrorMessageDeserializer.class) private ErrorMessageWrapper errorMessage; // Getter & Setter public String getErrorType() { return errorType; } public void setErrorType(String errorType) { this.errorType = errorType; } public ErrorMessageWrapper getErrorMessage() { return errorMessage; } public void setErrorMessage(ErrorMessageWrapper errorMessage) { this.errorMessage = errorMessage; } }
步骤4:测试反序列化
使用Jackson的ObjectMapper进行反序列化测试:
import com.fasterxml.jackson.databind.ObjectMapper; public class DeserializeTest { public static void main(String[] args) throws IOException { ObjectMapper mapper = new ObjectMapper(); // 测试变体1 String json1 = "{\"errorMessage\": \"系统异常\"}"; ErrorResponse res1 = mapper.readValue(json1, ErrorResponse.class); System.out.println("变体1消息:" + res1.getErrorMessage().getSimpleMessage()); // 测试变体2 String json2 = "{\"errorType\": \"VALIDATION\", \"errorMessage\": \"参数格式错误\"}"; ErrorResponse res2 = mapper.readValue(json2, ErrorResponse.class); System.out.println("变体2类型:" + res2.getErrorType() + ",消息:" + res2.getErrorMessage().getSimpleMessage()); // 测试变体3 String json3 = "{\"errorType\": \"BUSINESS\", \"errorMessage\": {\"code\": \"BIZ-001\", \"message\": \"库存不足\"}}"; ErrorResponse res3 = mapper.readValue(json3, ErrorResponse.class); if (!res3.getErrorMessage().isSimpleMessage()) { ErrorMessageDetail detail = res3.getErrorMessage().getDetailMessage(); System.out.println("变体3类型:" + res3.getErrorType() + ",错误码:" + detail.getCode() + ",消息:" + detail.getMessage()); } } }
方案2:直接使用Object字段(快速实现)
如果不想写自定义反序列化器,可以直接将errorMessage定义为Object类型,在代码中通过类型判断来处理不同情况:
定义主响应类
public class ErrorResponse { private String errorType; private Object errorMessage; // Getter & Setter public String getErrorType() { return errorType; } public void setErrorType(String errorType) { this.errorType = errorType; } public Object getErrorMessage() { return errorMessage; } public void setErrorMessage(Object errorMessage) { this.errorMessage = errorMessage; } }
测试反序列化
import com.fasterxml.jackson.databind.ObjectMapper; public class QuickDeserializeTest { public static void main(String[] args) throws IOException { ObjectMapper mapper = new ObjectMapper(); String json3 = "{\"errorType\": \"BUSINESS\", \"errorMessage\": {\"code\": \"BIZ-001\", \"message\": \"库存不足\"}}"; ErrorResponse res3 = mapper.readValue(json3, ErrorResponse.class); if (res3.getErrorMessage() instanceof String) { System.out.println("字符串消息:" + (String) res3.getErrorMessage()); } else if (res3.getErrorMessage() instanceof ErrorMessageDetail) { ErrorMessageDetail detail = (ErrorMessageDetail) res3.getErrorMessage(); System.out.println("错误码:" + detail.getCode() + ",消息:" + detail.getMessage()); } } }
这种方式的缺点是类型判断分散在业务代码中,长期维护性不如方案1,但实现速度快,适合简单场景。
内容的提问来源于stack exchange,提问作者Web Nerd
相关产品推荐
相关产品推荐

