FastJSON通过SerializeFilter定制序列化

FastJSON通过SerializeFilter定制序列化

官方wiki:https://github.com/alibaba/fastjson/wiki/SerializeFilter

案例

本文将以一下json举例

{
  "store": {
    "book": [
      {
        "category": "reference",
        "author": "Nigel Rees",
        "title": "Sayings of the Century",
        "price": 8.95
      },
      {
        "category": "fiction",
        "author": "Evelyn Waugh",
        "title": "Sword of Honour",
        "price": 12.99
      }
    ],
    "bicycle": {
      "color": "red",
      "price": 19.95
    }
  },
  "expensive": 10
}

需求:过滤掉其中book对象的 price属性。

SimplePropertyPreFilter 过滤器(官方实现)

package com.alibaba.fastjson.serializer;

import java.util.HashSet;
import java.util.Set;

public class SimplePropertyPreFilter implements PropertyPreFilter {
    private final Class<?> clazz;
    private final Set<String> includes;
    private final Set<String> excludes;
    private int maxLevel;

    public SimplePropertyPreFilter(String... properties) {
        this((Class)null, properties);
    }

    public SimplePropertyPreFilter(Class<?> clazz, String... properties) {
        this.includes = new HashSet();
        this.excludes = new HashSet();
        this.maxLevel = 0;
        this.clazz = clazz;
        String[] var3 = properties;
        int var4 = properties.length;

        for(int var5 = 0; var5 < var4; ++var5) {
            String item = var3[var5];
            if (item != null) {
                this.includes.add(item);
            }
        }

    }

    public int getMaxLevel() {
        return this.maxLevel;
    }

    public void setMaxLevel(int maxLevel) {
        this.maxLevel = maxLevel;
    }

    public Class<?> getClazz() {
        return this.clazz;
    }

    public Set<String> getIncludes() {
        return this.includes;
    }

    public Set<String> getExcludes() {
        return this.excludes;
    }

    public boolean apply(JSONSerializer serializer, Object source, String name) {
        if (source == null) {
            return true;
        } else if (this.clazz != null && !this.clazz.isInstance(source)) {
            return true;
        } else if (this.excludes.contains(name)) {
            return false;
        } else {
            if (this.maxLevel > 0) {
                int level = 0;

                for(SerialContext context = serializer.context; context != null; context = context.parent) {
                    ++level;
                    if (level > this.maxLevel) {
                        return false;
                    }
                }
            }

            return this.includes.size() == 0 || this.includes.contains(name);
        }
    }
}

测试demo

String json = "{\"store\":{\"book\":[{\"category\":\"reference\",\"author\":\"Nigel Rees\",\"title\":\"Sayings of the Century\",\"price\":8.95},{\"category\":\"fiction\",\"author\":\"Evelyn Waugh\",\"title\":\"Sword of Honour\",\"price\":12.99}],\"bicycle\":{\"color\":\"red\",\"price\":19.95}},\"expensive\":10}";
SimplePropertyPreFilter filter = new SimplePropertyPreFilter();
filter.getExcludes().add("price");
JSONObject jsonObject = JSON.parseObject(json);
String str = JSON.toJSONString(jsonObject, filter);
System.out.println(str);

运行结果:

{
  "store": {
    "bicycle": {
      "color": "red",
      "price": 19.95
    },
    "book": [
      {
        "author": "Nigel Rees",
        "category": "reference",
        "title": "Sayings of the Century"
      },
      {
        "author": "Evelyn Waugh",
        "category": "fiction",
        "title": "Sword of Honour"
      }
    ]
  },
  "expensive": 10
}

查看 JSON 数据的过滤结果,发现 bicycle中的 price属性也被过滤掉了,不符合需求。

定制PropertyPreFilter实现层级过滤

import java.util.HashSet;
import java.util.Set;

import com.alibaba.fastjson.serializer.JSONSerializer;
import com.alibaba.fastjson.serializer.PropertyPreFilter;
import com.alibaba.fastjson.serializer.SerialContext;

/**
 * description
 *
 * @author Gravity 2020/05/30 15:37
 */
public class LevelPropertyPreFilter implements PropertyPreFilter {

    private final Class<?> clazz;
    private final Set<String> includes = new HashSet<String>();
    private final Set<String> excludes = new HashSet<String>();
    private int maxLevel = 0;

    public LevelPropertyPreFilter(String... properties) {
        this(null, properties);
    }

    public LevelPropertyPreFilter(Class<?> clazz, String... properties) {
        super();
        this.clazz = clazz;
        for (String item : properties) {
            if (item != null) {
                this.includes.add(item);
            }
        }
    }

    public LevelPropertyPreFilter addExcludes(String... filters) {
        for (String filter : filters) {
            this.getExcludes().add(filter);
        }
        return this;
    }

    public LevelPropertyPreFilter addIncludes(String... filters) {
        for (String filter : filters) {
            this.getIncludes().add(filter);
        }
        return this;
    }

    public boolean apply(JSONSerializer serializer, Object source, String name) {
        
        if (source == null) { //对象为空。直接放行
            return true;
        }

        if (clazz != null && !clazz.isInstance(source)) { //当前需要序列化的对象的类对象为空。直接放行
            return true;
        }

        SerialContext serialContext = serializer.getContext();
        String levelName = serialContext.toString();
        levelName = levelName + "." + name;
        levelName = levelName.replace("$.", ""); //去除开头的$.
        levelName = levelName.replaceAll("\\[\\d+\\]", ""); //去除掉[] 如果是数组的话有有这个存在

        if (this.excludes.contains(levelName)) { // 判断是否被排除
            return false;
        }

        if (includes.size() == 0 || includes.contains(levelName)) { // 判断是否被开放
            return true;
        }

        if (maxLevel > 0) {
            int level = 0;
            SerialContext context = serializer.getContext();
            while (context != null) {
                level++;
                if (level > maxLevel) {
                    return false;
                }
                context = context.parent;
            }
        }

        return false;
    }

    public int getMaxLevel() {
        return maxLevel;
    }

    public void setMaxLevel(int maxLevel) {
        this.maxLevel = maxLevel;
    }

    public Class<?> getClazz() {
        return clazz;
    }

    public Set<String> getIncludes() {
        return includes;
    }

    public Set<String> getExcludes() {
        return excludes;
    }
    
}

测试demo

String json = "{\"store\":{\"book\":[{\"category\":\"reference\",\"author\":\"Nigel Rees\",\"title\":\"Sayings of the Century\",\"price\":8.95},{\"category\":\"fiction\",\"author\":\"Evelyn Waugh\",\"title\":\"Sword of Honour\",\"price\":12.99}],\"bicycle\":{\"color\":\"red\",\"price\":19.95}},\"expensive\":10}";
JSONObject jsonObj = JSON.parseObject(json);
LevelPropertyPreFilter filter = new LevelPropertyPreFilter();
filter.addExcludes("store.book.price"); // 排除属性
String result = JSON.toJSONString(jsonObj, filter);
log.info(result);

运行结果

{
  "store": {
    "bicycle": {
      "color": "red",
      "price": 19.95
    },
    "book": [
      {
        "author": "Nigel Rees",
        "category": "reference",
        "title": "Sayings of the Century"
      },
      {
        "author": "Evelyn Waugh",
        "category": "fiction",
        "title": "Sword of Honour"
      }
    ]
  },
  "expensive": 10
}

同理,也可实现只返回book对象的 price属性。

String json = "{\"store\":{\"book\":[{\"category\":\"reference\",\"author\":\"Nigel Rees\",\"title\":\"Sayings of the Century\",\"price\":8.95},{\"category\":\"fiction\",\"author\":\"Evelyn Waugh\",\"title\":\"Sword of Honour\",\"price\":12.99}],\"bicycle\":{\"color\":\"red\",\"price\":19.95}},\"expensive\":10}";
JSONObject jsonObj = JSON.parseObject(json);
LevelPropertyPreFilter filter = new LevelPropertyPreFilter();
filter.addIncludes("store.book.price"); // 开放属性
String result = JSON.toJSONString(jsonObj, filter);
log.info(result);

运行结果

{
  "store": {
    "book": [
      {
        "price": 8.95
      },
      {
        "price": 12.99
      }
    ]
  }
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
fastjson 2.0.0版本提供了多种反序列化配置,可以通过配置来控制反序列化的行为,以增强安全性和灵活性。以下是常见的反序列化配置: 1. AutoType:开启该配置后,fastjson将支持反序列化任何Java,包括未知的、不在白名单中的。这个配置存在安全隐患,因为攻击者可以通过构造恶意的JSON字符串来执行任意代码。因此,建议仅在必要时才开启该配置,并通过白名单过滤掉非法。 2. ParserConfig:该配置用于管理反序列化时的解析器配置,包括白名单、黑名单、自定义序列化器等。通过ParserConfig可以实现更精细的反序列化控制。 3. Feature:该配置用于开启或关闭fastjson的一些特性,如自动型匹配、允许注释、允许单引号等。通过Feature可以灵活地控制反序列化的行为。 4. ASM:该配置用于开启或关闭fastjson的ASM字节码增强功能,以提高反序列化性能。默认情况下,fastjson会尝试使用ASM来优化反序列化代码,但在某些环境下可能会造成兼容性问题。 5. SerializeConfig:该配置用于序列化时的配置管理,包括白名单、黑名单、自定义序列化器等。通过SerializeConfig可以实现更精细的序列化控制。 这些配置可以通过调用JSON的静态方法来设置,例如: ``` JSON.DEFAULT_PARSER_FEATURE |= Feature.AutoCloseSource.getMask(); JSON.DEFAULT_PARSER_FEATURE &= ~Feature.UseBigDecimal.getMask(); ``` 注意,反序列化配置应该根据具体情况进行选择和设置,以确保安全和性能。建议仔细阅读fastjson的官方文档,并参考相关的安全规范和最佳实践。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值