一些收藏

jackson注解的使用

2021-11-11  本文已影响0人  随风_d6a2

@JsonCreator 注解

该注解用在对象的反序列时指定特定的构造函数或者工厂方法。在反序列化时,Jackson默认会调用对象的无参构造函数,如果我们不定义任何构造函数,Jvm会负责生成默认的无参构造函数。但是如果我们定义了构造函数,并且没有提供无参构造函数时,Jackson会报错:

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `com.liyao.model.Person` (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator)
 at [Source: (String)"{"age":1,"name":"ly","address":["1","2","3"]}"; line: 1, column: 2]

再回到@JsonCreator注解,其作用就是,指定对象反序列化时的构造函数或者工厂方法,如果默认构造函数无法满足需求,或者说我们需要在构造对象时做一些特殊逻辑,可以使用该注解。该注解需要搭配@JsonProperty使用。

举例:

public class Person {
 
    private int age;
    private String name;
 
    @JsonCreator
    public Person(@JsonProperty("age") int age, @JsonProperty("name") String name) {
        this.age = age;
        this.name = name;
    }
}

如上是只用@JsonCreator注解的例子,可以直接反序列化。

如果不使用该注解,那么需要提供无参构造函数以及对应的setter方法:

public class Person {

private int age;
private String name;

public int getAge() {
    return age;
}

public void setAge(int age) {
    this.age = age;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

}
当然二者可以协同使用,就是在@JsonCreator方法里提供部分属性的初始化方法,剩余的通过setter方法提供,建议只选一种。

推荐使用@JsonCreator注解提供反序列化方法,这样表意更清晰,减少了类的方法数目。

但是需要注意:

@JsonCreator只能用在静态方法或者构造方法,实例方法是不行的!!!因为还没构造出对象。

另外,类似的还有一个@ConstructorProperties注解也是类似的,不过只能用在构造函数里。

再贴一个例子:

public class ConfigModel {
 
    private long id;
    private String name;
 
    /**
     * 方式一:使用static方法,需要将入参使用@JsonProperty("xxx")注解标注,jackson才能知道属性怎么对应
     */
    @JsonCreator
    public static ConfigModel create(@JsonProperty("id") long id, @JsonProperty("name") String name) {
        ConfigModel model = new ConfigModel();
        model.setId(id);
        model.setName(name);
        System.out.println("factory");
        return model;
    }
 
    /**
     * 方式二:使用构造方法,同样需要将入参使用@JsonProperty("xxx")注解标注
     */
    @JsonCreator
    public ConfigModel(@JsonProperty("id") long id, @JsonProperty("name") String name) {
        ConfigModel model = new ConfigModel();
        model.setId(id);
        model.setName(name);
        System.out.println("constructor1");
    }
 
    /**
     * 方式三:使用构造方法,使用ConstructorProperties注解标识属性顺序,无需再使用@JsonProperty
     */
    @ConstructorProperties({"id", "name"})
    public ConfigModel(long id, String name) {
        ConfigModel model = new ConfigModel();
        model.setId(id);
        model.setName(name);
        System.out.println("constructor2");
    }
 
    public ConfigModel() {
        // default
    }
 
    public long getId() {
        return id;
    }
 
    public void setId(long id) {
        this.id = id;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
}

测试

@Test
    public void test1(){
        ObjectMapper objectMapper = new ObjectMapper();
        String carJson ="{ \"age1\" : 111,\"name2\" : \"hhh\"}";
        try {
            Person dog = objectMapper.readValue(carJson, Person.class);
            System.out.println(dog);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

@JsonAnyGetter和@JsonAnySetter

@JsonAnySetter 用于属性或者方法,设置未反序列化的属性名和值作为键值存储到 map 中;
@JsonAnyGetter 用于方法 ,获取所有未序列化的属性;

场景:在调用第三方接口时,对方接口可能会新增或者修改一些参数,你这边代码怎么做适配才能把所有参数接收到?@JsonAnyGetter和@JsonAnySetter可以很好解决,在不修改代码的情况下接收新增或者修改的参数。

接收到json字符串

String s = "[{\"s\":\"hah\",\"b\":\"hehe\",\"uuid\":\"uuid\",\"name\":\"213\"}]";

uuid和name是必传的,但是s和b这两个字段可能是变化的扩展字段,我们要怎么在代码里去适配获取这两个字段呢?
使用@JsonAnyGetter和@JsonAnySetter可以完美解决

public class User2Info {
    public User2Info(){
    }
    public User2Info(String uuid, String name){
        this.uuid = uuid;
        this.name = name;
    }
    private String uuid;
    private String name;

    private Map<String,Object> other = new HashMap<>();

    public String getUuid() {
        return uuid;
    }

    public void setUuid(String uuid) {
        this.uuid = uuid;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @JsonAnyGetter
    public Map<String, Object> getOther() {
        return other;
    }

    /**
     * 没有匹配上的反序列化属性,放到这里
     * @param key
     * @param value
     */
    @JsonAnySetter
    public void setOther(String key, Object value) {
        this.other.put(key,value);
    }

试试看:

public static void main(String[] args){
        String s = "[{\"s\":\"hah\",\"b\":\"hehe\",\"uuid\":\"uuid\",\"name\":\"213\"}]";
        TypeReference<List<User2Info>> infos = new TypeReference<List<User2Info>>(){};
        List<User2Info> user2Infos = JsonUtil.toPojo(s, infos);
        String l = JsonUtil.toJson(user2Infos);
        System.out.println("json2:"+l);
    }

输出:json2:[{“uuid”:“uuid”,“name”:“213”,“b”:“hehe”,“s”:“hah”}]
我们将@JsonAnyGetter去掉试试看

    public Map<String, Object> getOther() {
        return other;
    }

输出:

json2:[{“uuid”:“uuid”,“name”:“213”,“other”:{“b”:“hehe”,“s”:“hah”}}]

多了一个other的json对象。

参考:
https://blog.csdn.net/qq_34308732/article/details/86736985

这个博客对jackson介绍的非常到位:
https://juejin.cn/post/6844904166809157639

上一篇 下一篇

猜你喜欢

热点阅读