jackson根据属性名动态序列化对象字段

在info上有篇文章讲的是 《为什么说 GraphQL 可以取代 REST API?》,里面提到这样一段:


图片.png

如果我们要实现这种方式:GET /users/?fields=name,address&include=resumes,subscriptions.按须只返回相应的字段值。
有几个点要考虑,今天我们只说其中的一个东西,这个问题就是要根据指定属性名来序列化对象的值。传统的方法都是通过 annotations来实现,但是这种方式使用方式很死,有没有一种方法可以不通过annotations来完成呢,那就是通过jackson的@JsonFilter和addMixIn()方法配合使用。下面我们一步步来完成这个功能。
第一步:我们须要定义一个实体类 User,它就是我们须要序列化的对象:

public class User {
    private String firstName;
    
    private String lastName;

    private String name;

    private Integer age;

    //getter setter
}

第二步:我们来创建一个通用的@JsonFilter对象,注意这个类没有任何属性:

@JsonFilter("userFilter")
public class UserFilter {
}

第三步:通过ObjectMapper默认提供的FilterProvider的实现类SimpleFilterProvider来配置相关的信息,并进行输出结果:

public class AppendTest {

    public static void main(String[] args) {
        User user = new User();
        user.setFirstName("water");
        user.setLastName("lang");
        user.setName("water lang");
        user.setAge(30);

        ObjectMapper objectMapper = new ObjectMapper();

        objectMapper.addMixIn(
                Object.class, UserFilter.class);

        FilterProvider filters = new SimpleFilterProvider()
                .addFilter("userFilter",
                        SimpleBeanPropertyFilter.serializeAllExcept(
                                "name"));
        ObjectWriter writer = objectMapper.writer(filters);

        try {
            System.out.println(writer.writeValueAsString(user));
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
    }
}

我们可以看到输出的结果为:
{"firstName":"water","lastName":"lang","age":30}
明显可以找到这个name这个字段没有被序列化出来。

如果我们要继续让这个序列化的字段进行动态改变怎么做呢?很简单,我们只须要再创建一个filterProvider就行了,然后通过writer()方法配置进去就行了。

package com.github.bohnman.squiggly.examples.springboot.test;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.ser.FilterProvider;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import com.github.bohnman.squiggly.examples.springboot.model.User;

public class AppendTest {

    public static void main(String[] args) {
        User user = new User();
        user.setFirstName("water");
        user.setLastName("lang");
        user.setName("water lang");
        user.setAge(30);

        ObjectMapper objectMapper = new ObjectMapper();

        objectMapper.addMixIn(
                Object.class, UserFilter.class);

        FilterProvider filters = new SimpleFilterProvider()
                .addFilter("userFilter",
                        SimpleBeanPropertyFilter.serializeAllExcept(
                                "name"));
        ObjectWriter writer = objectMapper.writer(filters);

        try {
            System.out.println(writer.writeValueAsString(user));
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

        FilterProvider ageFilter = new SimpleFilterProvider()
                .addFilter("userFilter",
                        SimpleBeanPropertyFilter.serializeAllExcept(
                                "age","lastName"));
        ObjectWriter writer1 =   objectMapper.writer(ageFilter);
        try {
            System.out.println(writer1.writeValueAsString(user));
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
    }
}

输出结果:
{"firstName":"water","lastName":"lang","age":30}
{"firstName":"water","name":"water lang"}

注意的是我们这里没有直接使用ObjectMapper来做而是使用的ObjectWriter类来实现。当jackson在2.x版本,官方推荐优先使用后者。还有一个就是ObjectMapper具体应该是单例还是对象池(比如apache的ObjectPool)还是每次创建一个在github有很多争议。如果并发量不是很大的情况下可以使用单例,在并发量很大的情况下推荐使用对象池来实现。
https://stackoverflow.com/questions/3907929/should-i-declare-jacksons-objectmapper-as-a-static-field

你可能感兴趣的:(jackson根据属性名动态序列化对象字段)