FastJson简单实现@JsonInclude效果,使得非空字段不返回

摘要:
简介:记录上一个项目中遇到的FastJson序列化问题。这个项目是基于springroot实现的。当接口返回数据时,FastJson完成实体类序列化。然而,由于功能要求,我不需要返回实体类中的一些空字段,但我不能将FastJson更改为序列化的大逻辑,也就是说,不能将FastJ的序列化替换为JackSon,但应该在JackSon中实现@JsonInclude注释。

引言:记录最近一次做项目过程中碰到的一个FastJson序列化的问题,本次项目基于spring boot实现,在接口返回数据的时候,实体类的序列化是由FastJson完成的,但是由于功能需要,我需要将某个实体类中的些为空的字段则不返回,但是不能改动FastJson作为序列化的大逻辑,也就是说不能将序列化由FastJson替换为JackSon,但是要实现Jackson中@JsonInclude注解的效果。

【注】FastJson默认是会将没赋值的属性不进行序列化,但是本项目中设置了FastJson将空值设为默认值的配置(例如:SerializerFeature.WriteNullNumberAsZero,SerializerFeature.WriteNullStringAsEmpty等),该配置不可更改,如果没配置,则本文内容就可以略过啦,你写的代码没有bug

解决方案:自定义注解+反射+自定义实现PropertyPreFilter接口实现

1、先简单介绍一下PropertyPreFilter接口

属性过滤器:使用PropertyPreFilter过滤属性

public interface PropertyPreFilter extends SerializeFilter {

    boolean apply(JSONSerializer serializer, Object object, String name);
}

FastJson官方通过SimplePropertyPreFilter实现了该接口,可用于排除一些字段,简单使用如下

public class TestVo implements Serializable {

    private static final long serialVersionUID = 4468516188008268414L;

    private Long id;

    private Integer age;

    private String name;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Integer getAge() {
        return age;
    }

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

    public String getName() {
        return name;
    }

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

    public static void main(String[] args) {
        TestVo testVo = new TestVo();
        testVo.setId(1L);
        testVo.setName("微雨");

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

        System.out.println(JSONObject.toJSONString(testVo, preFilter, SerializerFeature.WriteNullNumberAsZero, SerializerFeature.WriteNullStringAsEmpty));

    }
}
返回结果:{"age":0,"id":1}
age返回默认值,name被排除

粗略研究一下SimplePropertyPreFilter接口实现apply()方法的源码,可以得出以下结论:如果某个字段需要排除,则直接返回false就好了

public boolean apply(JSONSerializer serializer, Object source, String name) {
    if (source == null) {
        return true;
    }

    if (clazz != null && !clazz.isInstance(source)) {
        return true;
    }

  // 重点代码,如果某个字段需要排除,则直接返回false就好了
if (this.excludes.contains(name)) { return false; } if (maxLevel > 0) { int level = 0; SerialContext context = serializer.context; while (context != null) { level++; if (level > maxLevel) { return false; } context = context.parent; } } if (includes.size() == 0 || includes.contains(name)) { return true; } return false; }

2、具体实现

思路:自定义一个注解,当序列化前,通过反射获取属性上是否有自定义注解,如果有,则获取属性的值,如果值为空则返回false,否则就返回true

自定义注解:

/**
* Description:该注解加在属性上,如果属性的值为空,则该属性不进行序列化返回
 * 参考Jackson的@JsonInclude注解
*/

@Target({ElementType.FIELD,ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME)
public @interface CustomizeJsonExclude { }

注入FastJsonHttpMessageConverter对象(controller层或方法如果加了@RestController或@ResponseBody注解,返回JSON数据的时候会自动调用fastjson进行序列化,不配置则默认采用StringHttpMessageConverter)

@Configuration
public class FastJsonConfiguration {

    @Bean
    public FastJsonHttpMessageConverter fastJsonHttpMessageConverter() {
        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();

        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(

                //保留map空的字段 | 如果保留的话,map 里面的值如果是null 则会保留null
//                SerializerFeature.WriteMapNullValue,
                // 将String类型的NULL转化为""
                SerializerFeature.WriteNullStringAsEmpty,
                // 将Number类型的NULL转化为0
                SerializerFeature.WriteNullNumberAsZero,
                // 将List类型的NULL转成[]
                SerializerFeature.WriteNullListAsEmpty,
                // 将Boolean类型的NULL转化为false
                SerializerFeature.WriteNullBooleanAsFalse,
                // 避免循环引用
                SerializerFeature.DisableCircularReferenceDetect
        );
        ValueFilter valueFilter = (object, name, value) -> {
            if (null == value){
                value = "";
            }
            return value;
        };

        /**
         * 关键代码,实现PropertyPreFilter中的apply()方法
         * 参数说明:
         * 1、serializer:不知道有啥用,没具体研究,有兴趣的小伙伴可自行研究
         * 2、source:需要序列化的对象
         * 3、name:对象中的字段名
         */
        PropertyPreFilter preFilter = (serializer, source, name) -> {
            if (source == null) {
                return true;
            }
            Class<?> clazz = source.getClass();
            try {
                Field field = clazz.getDeclaredField(name);
                if (!field.isAccessible()){
                    field.setAccessible(true);
                }
          // 判断字段上有没有自定义注解CustomizeJsonExclude CustomizeJsonExclude annotation
= field.getAnnotation(CustomizeJsonExclude.class); if (Objects.nonNull(annotation)){
            // 获取字段的值,判断是否为空 Object value
= field.get(source); return Objects.nonNull(value); } } catch (Exception e) { e.printStackTrace(); } return true; }; fastJsonConfig.setSerializeFilters(preFilter,valueFilter); converter.setDefaultCharset(Charset.forName("UTF-8")); converter.setFastJsonConfig(fastJsonConfig); List<MediaType> mediaTypeList = new ArrayList<>(); // 解决中文乱码问题,相当于在Controller上的@RequestMapping中加了个属性produces = "application/json" mediaTypeList.add(MediaType.APPLICATION_JSON); converter.setSupportedMediaTypes(mediaTypeList); return converter; } }

3、效果

public class FinalSearchResult implements SearchResult, Serializable {

    private static final long serialVersionUID = -9084386156922106357L;

    @CustomizeJsonExclude
    private ProductSearchRepVo productRep;

    @CustomizeJsonExclude
    private String priceResult;

    @CustomizeJsonExclude
    private String articleResult;

    public ProductSearchRepVo getProductRep() {
        return productRep;
    }

    public void setProductRep(ProductSearchRepVo productRep) {
        this.productRep = productRep;
    }

    public String getPriceResult() {
        return priceResult;
    }

    public void setPriceResult(String priceResult) {
        this.priceResult = priceResult;
    }

    public String getArticleResult() {
        return articleResult;
    }

    public void setArticleResult(String articleResult) {
        this.articleResult = articleResult;
    }
}

返回结果:

FastJson简单实现@JsonInclude效果,使得非空字段不返回第1张

 FastJson简单实现@JsonInclude效果,使得非空字段不返回第2张

 返回结果达到预期

----------------------------------------------------

附:本次分享内容如果有不正确的地方,欢迎各位留言指正

免责声明:文章转载自《FastJson简单实现@JsonInclude效果,使得非空字段不返回》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇squid各种超时配置项详解Unity + NGUI 实现人物头顶UI的信息展示下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

PerformanceCounter 基本介绍以及示例方法

一 PerformanceCounter 基本介绍 1 简单介绍 表示 Windows NT 性能计数器组件 命名空间:System.Diagnostics 程序集:System(在 system.dll 中) 2 构造函数(只介绍本文要用到的) PerformanceCounter (String, String, String) 功能: 初始化 P...

go语言——实现函数名到函数处理的映射关系(反射的应用)

模拟这样一个场景:当我们知道我们要执行操作的名字,让其作为参数传入,如何通过这个名字取执行相应的函数处理呢? 解决方法:(这里设定一个结构A,其变量a,实现相应函数为fun1、fun2)   ①:首先在编码过程中,我们可以将相应的处理函数进行“同一结构”实现,让其函数名和相应处理函数用map结构形成映射;   ②:通过创建该结构体的变量,通过反射(vf :...

【Android】是时候为你的应用加上WebDav同步了

WebDav是什么? WebDAV (Web-based Distributed Authoring and Versioning) 一种基于HTTP1.1协议的通信协议。它扩展了HTTP 1.1,在GET、POST、HEAD等几个HTTP标准方法以外添加了一些新的方法,使应用程序可对Web Server直接读写,并支持写文件锁定(Locking)及解锁(...

SpringBoot整合Shiro 二:Shiro配置类

  环境搭建见上篇:SpringBoot整合Shiro 一:搭建环境   Shiro配置类配置 shiro的配置主要集中在 ShiroFilterFactoryBean 中       关于权限:   anon:无需认证就可以访问 ​  authc:必须认证了才能访问​   user:必须用有了 记住我 功能才能用​   perms:拥有对某个资源的...

java加解密(一)

1、杂谈   1、古典密码学     核心:替换法/位移法(凯撒加密)     破解方法:频率分析法,即研究字母和字母组合在文本中出现的概率。   2、近代密码学:     恩尼格玛机     被图灵破解   3、现代密码学:     1、散列函数:散列函数,也叫杂凑函数、摘要函数或哈希函数,可将任意长度的消息经过运算,变成固定长度数值,常...

C# 基本数据类型

Ø  前言 每个编程语言都有基本的数据类型,例如 C、C++、Java、Python、PHP、JavaScript、以及各种数据库等,而 C# 也不例外。本篇主要讨论 C# 中的一些常用的基础数据类型。   1.   值类型 Ø  值类型隐式继承于 System.ValueType,而 System.ValueType 隐式继承于 System.Objec...