Fastjson过滤字段、排除字段的5种方法

在序列化对象时,过滤字段是一个非常常见的需求。Fastjson提供了多种方式来支持对字段的包含和排除,既可以使用预定义的注解和过滤器,也可以自定义过滤器来实现特定的过滤规则。

本篇内容基于Fastjson 1.2.62版本,马上开始学习吧。

1.通过注解指定不需要序列化的字段

在不需要序列化的字段,添加@JSONField(serialize = false)注解可进行排除。

public class DontSerializeAnnotation {

    @JSONField(serialize = false)
    private Long id;
    private String name;

    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;
    }
}

/**
 * 通过注解指定不需要序列化的字段:@JSONField(serialize = false)
 */
@Test
public void testDontSerializeAnnotation() {
    DontSerializeAnnotation guestUser = new DontSerializeAnnotation();
    guestUser.setId(2L);
    guestUser.setName("guest");
    System.out.println(JSON.toJSONString(guestUser));
}

执行结果:

{"name":"guest"}

2.声明为transient的变量不进行序列化

如果被序列化的字段使用transient修饰,则不会被序列化。

public class TransientObject {

    private Long id;
    private transient String name;

    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;
    }
}

/**
 * 声明为transient的变量不进行序列化
 */
@Test
public void testTransientObject() {
    TransientObject guestUser = new TransientObject();
    guestUser.setId(2L);
    guestUser.setName("guest");
    System.out.println(JSON.toJSONString(guestUser));
}

执行结果:

{"id":2}

3.使用属性过滤器排除不需要序列化的字段

使用过滤器SimplePropertyPreFilter,可以一次性设置1到多个需要过滤掉的字段。

3.1 过滤对象中的某个字段

public class User {

    private Long id;
    private String name;

    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 testExcludeSingleFilter() {
    User guestUser = new User();
    guestUser.setId(2L);
    guestUser.setName("guest");

    SimplePropertyPreFilter filter = new SimplePropertyPreFilter();
    filter.getExcludes().add("name"); // 排除字段名为name的字段

    System.out.println(JSON.toJSONString(guestUser, filter));
}

执行结果:

{"id":2}

3.2 过滤嵌套类中的相同名字的字段

Group中的User,参照上一小节。

public class Group {

    private Long id;
    private String name;
    private List<User> users = new ArrayList<User>();

    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;
    }

    public List<User> getUsers() {
        return users;
    }

    public void setUsers(List<User> users) {
        this.users = users;
    }

    public void addUser(User user) {
        users.add(user);
    }
}

/**
 * 使用属性过滤器排除不需要序列化的字段.
 * 对于嵌套多层的类,不同类中具有相同名称的字段都会被过滤掉。
 */
@Test
public void testExcludeEmbedFilter() {
    Group group = new Group();
    group.setId(0L);
    group.setName("admin");

    User guestUser = new User();
    guestUser.setId(2L);
    guestUser.setName("guest");

    User rootUser = new User();
    rootUser.setId(3L);
    rootUser.setName("root");

    group.addUser(guestUser);
    group.addUser(rootUser);

    SimplePropertyPreFilter filter = new SimplePropertyPreFilter();
    filter.getExcludes().add("name");

    System.out.println(JSON.toJSONString(group, filter));
}

执行结果:

{"id":0,"users":[{"id":2},{"id":3}]}

3.3 使用多个属性过滤器排除不需要序列化的字段

如果只想过滤特定类中的字段,可以在创建过滤器的时候,指定对应类的class对象和字段。

下面示例,分别对Group和User创建一个过滤器,过滤掉不同的字段。

/**
 * 使用多个属性过滤器排除不需要序列化的字段.
 */
@Test
public void testExcludeMultiFilter() {
    Group group = new Group();
    group.setId(0L);
    group.setName("admin");

    User guestUser = new User();
    guestUser.setId(2L);
    guestUser.setName("guest");

    User rootUser = new User();
    rootUser.setId(3L);
    rootUser.setName("root");

    group.addUser(guestUser);
    group.addUser(rootUser);

    // Group的过滤器,过滤掉id字段
    SimplePropertyPreFilter filter1 = new SimplePropertyPreFilter(Group.class);
    filter1.getExcludes().add("id");
    // User的过滤器,过滤掉name字段
    SimplePropertyPreFilter filter2 = new SimplePropertyPreFilter(User.class);
    filter2.getExcludes().add("name");

    System.out.println(JSON.toJSONString(group, new SimplePropertyPreFilter[] {filter1, filter2}));
}

执行结果:

{"name":"admin","users":[{"id":2},{"id":3}]}

4.使用属性过滤器包含需要序列化的字段.

有些时候,我们仅仅需要序列化个别字段,或者当需要排除的字段比序列化的字段还要多的时候,这时可以使用包含而非排除的过滤器。

/**
 * 使用属性过滤器包含需要序列化的字段.
 */
@Test
public void testIncludeMultiFilter() {
    Group group = new Group();
    group.setId(0L);
    group.setName("admin");

    User guestUser = new User();
    guestUser.setId(2L);
    guestUser.setName("guest");

    User rootUser = new User();
    rootUser.setId(3L);
    rootUser.setName("root");

    group.addUser(guestUser);
    group.addUser(rootUser);

    // Group只序列化id和users
    SimplePropertyPreFilter filter1 = new SimplePropertyPreFilter(Group.class, "id", "users");
    // User只序列化name
    SimplePropertyPreFilter filter2 = new SimplePropertyPreFilter(User.class);
    filter2.getIncludes().add("name");

    System.out.println(JSON.toJSONString(group, new SimplePropertyPreFilter[] {filter1, filter2}));
}

执行结果:

{"id":0,"users":[{"name":"guest"},{"name":"root"}]}

5.自定义属性过滤规则

在某些特殊的场景下,以上简单的排除或包含方式,并不能很好的满足实际的应用需求。

这时,可以考虑通过自定义属性过滤器,来实现过滤。这种实现方式非常灵活,可以根据实际的需求进行实现。

可以对类、字段名和字段值执行某种规则判断,来决定是否需要进行序列化。

具体方法,是实现PropertyFilter接口中的apply方法,返回true表示包含该字段,返回false表示过滤掉。

/**
 * @author wenshao[szujobs@hotmail.com]
 */
public interface PropertyFilter extends SerializeFilter {

    /**
     * @param object the owner of the property. 字段所属的对象
     * @param name the name of the property. 字段名
     * @param value the value of the property. 字段值
     * @return true if the property will be included, false if to be filtered out
     */
    boolean apply(Object object, String name, Object value);
}
/**
 * 自定义属性过滤规则,最灵活的一种实现字段和值过滤的方式。
 */
@Test
public void testPropertyFilter() {
    Group group = new Group();
    group.setId(0L);
    group.setName("admin");

    User guestUser = new User();
    guestUser.setId(2L);
    guestUser.setName("guest");

    User rootUser = new User();
    rootUser.setId(3L);
    rootUser.setName("root");

    group.addUser(guestUser);
    group.addUser(rootUser);

    PropertyFilter filter = new PropertyFilter() {
        @Override
        public boolean apply(Object object, String name, Object value) {
            //System.out.println(object + " " + name + " " + value);
            if (name.equals("name")) {
                return false; // 排除名为name的字段
            }
            if (value.toString().equals("2")) {
                return false; // 排除值为2的字段
            }
            return true; // 包含该字段或值
        }
    };

    System.out.println(JSON.toJSONString(group, filter));
}

执行结果:

{"id":0,"users":[{},{"id":3}]}

小结

本篇讲了几种过滤字段的方式:

1.通过JSONField注解和transient关键字,可以用来过滤单个字段;
2.使用属性过滤器SimplePropertyPreFilter,可以包含或排除多个字段;
3.对于一些特殊的场景,可以考虑通过自定义属性过滤器,来实现过滤。这种实现方式非常灵活,可以根据实际的需求进行实现。可以对类、字段名和字段值执行某种规则判断,来决定是否需要进行序列化。

参考

《轻松学习Fastjson》

https://github.com/alibaba/fastjson


---转载本站文章请注明作者和出处 996极客教程(996geek.com),请勿用于任何商业用途---

留下评论