首页 前端知识 @JsonCreator和@JsonValue

@JsonCreator和@JsonValue

2024-05-05 22:05:05 前端知识 前端哥 540 521 我要收藏

文章目录

  • 1、正常反序列化的过程
  • 2、@JsonCreator
  • 3、@JsonValue
  • 4、应用:枚举类中校验传参以及优化前后端数据交互
  • 5、补充:@ConstructorProperties

1、正常反序列化的过程

反序列化时,默认会调用实体类的无参构造来实例化一个对象,然后使用setter来初始化属性值。写点测试代码:

@AllArgsConstructor
@Data
public class Book {
private String name;
private Double price;
}
复制

测试下:

public class TestSome1 {
@Test
void testJson() throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
Book book = objectMapper.readValue("{\n" +
" \"name\":\"Java\",\n" +
" \"price\":666.00\n" +
"}", Book.class);
System.out.println(book);
}
}
复制

此时,运行会抛出InvalidDefinitionException:

在这里插入图片描述

2、@JsonCreator

@JsonCreator可用在:

  • 构造方法上
  • 静态的工厂方法上

加了@JsonCreator注解,该类的对象在反序列化时,就走有@JsonCreator注解的方法来反序列化,原先无参+set的过程失效。

上面的Book类,可改成:

//@AllArgsConstructor
@Getter
public class Book {
private String name;
private Double price;
@JsonCreator
public Book(@JsonProperty("name") String name,@JsonProperty("price") Double price ){
System.out.println("@JsonCreator生效");
this.name = name;
this.price = price+1;
}
}
复制

上面的@JsonProperty注解就是指定传参名和对象属性关系的,有点像MyBatis的@Param

public Book(@JsonProperty("name") String name,@JsonProperty("price") Double price ){
复制

@JsonCreator放在静态方法上就是:

@AllArgsConstructor
@Getter
public class Book {
private String name;
private Double price;
@JsonCreator
public static Book unSerialize(){
System.out.println("正在反序列化成对象");
return new Book("111",1.00);
}
}
复制

以@JsonCreator放在构造方法上为例,再运行前面的单元测试,看下反序列化的效果:

在这里插入图片描述

3、@JsonValue

@JsonValue注解可用在:

  • get方法
  • 属性字段上

一个类只能用一个,加上这个注解时,该类的对象序列化时就会只返回这个字段的值做为序列化的结果。

比如一个枚举类的get方法上加上该注解,那么在序列化这个枚举类的对象时,返回的就是枚举对象的这个属性,而不是这个枚举对象的序列化json串。继续改造上面的Book类:

@AllArgsConstructor
@Getter
public class Book {
//@JsonValue,加get方法或者这个属性上,都一样
private String name;
private Double price;
@JsonCreator
public static Book doSerialize(){
System.out.println("正在反序列化成对象");
return new Book("111",1.00);
}
/**
* 序列化时,序列化成我return的值,即当前对象的name属性
*/
@JsonValue
public String getName(){
return this.name;
}
}
复制

单元测试中看下效果:

public class TestSome1 {
@Test
void testJson() throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
Book book = objectMapper.readValue("{\n" +
" \"name\":\"Java\",\n" +
" \"price\":666.00\n" +
"}", Book.class);
System.out.println(book);
System.out.println("=======");
//序列化
System.out.println(objectMapper.writeValueAsString(book));
}
}
复制

在这里插入图片描述

4、应用:枚举类中校验传参以及优化前后端数据交互

比如定义一个排序字段的枚举类,排序字段要拼到mapper层的SQL,所以其传参的合法性必须校验,每次在Service层校验,很繁琐。引入@JsonCreator:

@AllArgsConstructor
@Getter
public enum OrderFieldEnum {
CREATE_TIME("createTime","create_time"),
USER_NAME("userName","user_name");
private final String value;
private final String field;
private static final Map<String,OrderFieldEnum> map = new HashMap<>(3);
@JsonCreator
public static OrderFieldEnum unSerializer(String value){
//把以value为key,以枚举对象为value,存进map
if(map.isEmpty()){
for (OrderFieldEnum fieldEnum : OrderFieldEnum.values()) {
map.put(fieldEnum.value,fieldEnum);
}
}
//map中找不到就是超出范围
if(!map.containsKey(value)){
throw new RuntimeException("超出范围");
}
return map.get(value);
}
@JsonValue
public String getValue(){
return this.value+"@JsonValue"; //这里刻意加个@JsonValue,方便后面验证序列化效果。return this.value就行。
}
}
复制

此时,前端传个dto(json)过来,dto里有个参数的类型是枚举类型,反序列化json成dto对象时,枚举类型的属性也会反序列化,上面@JsonCreator定义的unSerializer方法执行,就会完成参数合法性校验,Service层省事了。至于序列化:

@JsonValue
public String getValue(){
return this.value;
}
复制

比如需要返给前端枚举值展示下拉框,就直接Vo里就直接List<Enum> enumList,而不用定义个List<String> enumList,再反复getValue:

enumList.add(ENUM1.getValue)
enumList.add(ENUM2.getValue)
...
复制

因为返给前端时,Vo对象序列化,里面的一个个枚举对象也序列化,而JsonValue已经指定了序列化枚举对象时就把它的value返回就行。写个简单接口看下效果,定义个dto:

@Data
public class JsonDto {
private String id;
private OrderFieldEnum orderField;
}
复制

Service层demo:

@Service
public class MyService {
public List<OrderFieldEnum> listValue(JsonDto dto){
System.out.println(dto.getOrderField());
//直`List<Enum>
List<OrderFieldEnum> list = List.of(OrderFieldEnum.CREATE_TIME, OrderFieldEnum.USER_NAME);
return list;
}
}
复制

controller:

@RestController
public class CodeController {
@Resource
private MyService myService;
@PostMapping("/test")
public List<OrderFieldEnum> getStr(@RequestBody JsonDto dto){
return myService.listValue(dto);
}
}
复制

异常传参时:

在这里插入图片描述

正常传参:

在这里插入图片描述

此时,不管枚举类型啥的,前端传个String就行。最后,注解的依赖坐标引对:

在这里插入图片描述

5、补充:@ConstructorProperties

在这里插入图片描述

转载请注明出处或者链接地址:https://www.qianduange.cn//article/7111.html
评论
还可以输入200
共0条数据,当前/页
发布的文章

JQuery中的load()、$

2024-05-10 08:05:15

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!