@JsonCreator和@JsonValue

27,701次阅读
没有评论

共计 3598 个字符,预计需要花费 9 分钟才能阅读完成。

文章目录

  • 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.00n" +
                "}", Book.class);
        System.out.println(book);
       
    }
}

此时,运行会抛出 InvalidDefinitionException:

@JsonCreator 和 @JsonValue

2、@JsonCreator

@JsonCreator 可用在:

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

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

上面的 Book 类,可改成:


@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 放在构造方法上为例,再运行前面的单元测试,看下反序列化的效果:

@JsonCreator 和 @JsonValue

3、@JsonValue

@JsonValue 注解可用在:

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

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

@AllArgsConstructor
@Getter
public class Book {

    
    private String name;

    private Double price;

    @JsonCreator
    public static Book doSerialize(){
        System.out.println("正在反序列化成对象");
        return new Book("111",1.00);
    }

    
    @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.00n" +
                "}", Book.class);
        System.out.println(book);
        System.out.println("=======");
        
        System.out.println(objectMapper.writeValueAsString(book));
    }
}

@JsonCreator 和 @JsonValue

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 MapString,OrderFieldEnum> map = new HashMap>(3);

    @JsonCreator
    public static OrderFieldEnum unSerializer(String value){
    	
        if(map.isEmpty()){
            for (OrderFieldEnum fieldEnum : OrderFieldEnum.values()) {
                map.put(fieldEnum.value,fieldEnum);
            }
        }
        
        if(!map.containsKey(value)){
            throw new RuntimeException("超出范围");
        }
        return map.get(value);
    }

    @JsonValue
    public String getValue(){
        return this.value+"@JsonValue";   
    }


}

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

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

比如需要返给前端枚举值展示下拉框,就直接 Vo 里就直接 List enumList,而不用定义个 List 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 ListOrderFieldEnum> listValue(JsonDto dto){
        System.out.println(dto.getOrderField());
        
        ListOrderFieldEnum> list = List.of(OrderFieldEnum.CREATE_TIME, OrderFieldEnum.USER_NAME);
        return list;
    }
}

controller:

@RestController
public class CodeController {

    @Resource
    private MyService myService;

    @PostMapping("/test")
    public ListOrderFieldEnum> getStr(@RequestBody JsonDto dto){

        return myService.listValue(dto);
    }
}

异常传参时:

@JsonCreator 和 @JsonValue

正常传参:

@JsonCreator 和 @JsonValue

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

@JsonCreator 和 @JsonValue

5、补充:@ConstructorProperties

在这里插入图片描述

原文地址: @JsonCreator 和 @JsonValue

    正文完
     0
    Yojack
    版权声明:本篇文章由 Yojack 于2024-09-30发表,共计3598字。
    转载说明:
    1 本网站名称:优杰开发笔记
    2 本站永久网址:https://yojack.cn
    3 本网站的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,请联系站长进行删除处理。
    4 本站一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
    5 本站所有内容均可转载及分享, 但请注明出处
    6 我们始终尊重原创作者的版权,所有文章在发布时,均尽可能注明出处与作者。
    7 站长邮箱:laylwenl@gmail.com
    评论(没有评论)