假设如下方法和对象
@Operation(summary = "新增或修改标签信息")
@PostMapping("saveOrUpdate")
public Result saveOrUpdateLabel(@RequestBody LabelInfo labelInfo) {
service.saveOrUpdate(labelInfo);
return Result.ok();
}
@Schema(description = "标签信息表")
@TableName(value = "label_info")
@Data
public class LabelInfo extends BaseEntity {
private static final long serialVersionUID = 1L;
@Schema(description = "类型")
@TableField(value = "type")
private ItemType type;
@Schema(description = "标签名称")
@TableField(value = "name")
private String name;
}
@Getter
@AllArgsConstructor
public enum ItemType implements BaseEnum {
APARTMENT(1, "公寓"),
ROOM(2, "房间");
@EnumValue
@JsonValue
private Integer code;
private String name;
}
在saveOrUpdateLabel方法中,如果不对ItemType对象的code变量添加@JsonValue注解,若前端发送{ "type": "2", "name": "两室一厅" }会报错
Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `com.sense.lease.model.enums.ItemType` from String "2": not one of the values accepted for Enum class: [APARTMENT, ROOM]]
此时ItemType的反序列化流程是什么样的?以及为什么是通过Jackson的@JsonValue实现反序列化而不是WebDataBinder的Converter?
首先,我们需要区分两种不同的转换场景:
?type=2WebDataBinder和Converter接口{"type": "2", "name": "两室一厅"}ObjectMapper当Spring Boot接收到包含JSON的请求体时,会发生以下过程:
HTTP请求到达:
POST /admin/label/saveOrUpdate
Content-Type: application/json
{
"type": "2",
"name": "两室一厅"
}
Jackson处理JSON:
ObjectMapper来解析JSON"type": "2"时,Jackson需要将其转换为ItemType枚举默认枚举反序列化:
@JsonValue注解告诉Jackson在进行序列化和反序列化时,应该使用哪个字段作为枚举的值:
public enum ItemType implements BaseEnum {
APARTMENT(1, "公寓"),
ROOM(2, "房间");
@EnumValue // MyBatis-Plus使用此注解确定存储到数据库的值
@JsonValue // Jackson使用此注解确定序列化/反序列化的值
private Integer code;
// ...
}
当添加了@JsonValue注解后:
ItemType.ROOM转换为JSON时,输出2而不是"ROOM""2"或者数字2转换为ItemType.ROOM对象Converter接口(如StringToItemTypeConverter)是为Spring MVC的WebDataBinder设计的,专门用于处理HTTP请求参数的转换,而不是JSON数据的反序列化。
两者的工作层面不同:
可以通过以下方式验证这个区别:
测试请求参数(使用Converter):
GET /admin/label/list?type=2
这个请求会使用StringToItemTypeConverter进行转换
测试JSON请求体(使用@JsonValue):
POST /admin/label/saveOrUpdate
Content-Type: application/json
{
"type": "2",
"name": "两室一厅"
}
这个请求会使用Jackson的反序列化机制,依赖于@JsonValue注解
除了使用@JsonValue,您还可以使用@JsonCreator注解提供自定义的反序列化方法:
// @JsonCreator注解指定自定义反序列化方法,静态工厂函数,根据code属性值返回对应的枚举对象实例
// 参数类型需与Json数据中code属性的数据类型一致,或者声明为Object类型,否则无法将json数据与参数绑定
// 参数名可直接使用Json数据中的属性名,否则需使用@JsonProperty注解指定属性名。
@JsonCreator
public static ItemType forValue(@JsonProperty("code") String c) {
for (ItemType type : ItemType.values()) {
if (type.getCode().equals(Integer.valueOf(c))) {
return type;
}
}
throw new IllegalArgumentException("code: " + c + "非法");
}
优点:灵活,可进行额外的处理流程
缺点:
@JsonValue注解时,JSON数据既可以是字符串也可以是数字Converter接口,由Spring MVC的WebDataBinder处理@JsonValue或@JsonCreator注解,不仅是请求体中的JSON数据反序列化,任何时候涉及到JSON数据反序列化,只要使用的是Spring Boot默认的ObejctMapper或配置了相同Jackson设置的ObejctMapper,相关注解都会生效。Converter和适当的Jackson注解
本文来自博客园,作者:青衫扶夕,转载请注明原文链接:https://www.cnblogs.com/qsswxm/p/19301027
登录查看全部
参与评论
手机查看
返回顶部