-
Notifications
You must be signed in to change notification settings - Fork 496
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[FEATURE]Filter功能兼容fastjson建议 #2590
Comments
这个是个问题,你能帮提供下更具体一点的代码么?另外这个周末出去玩,估计要晚几天才能处理哈 |
fastjson中实现参数过滤示例 public class FilterDemo implements PropertyPreFilter, PropertyFilter, ValueFilter {
private final IdentityHashMap<Object, String> objectPathMap = new IdentityHashMap<>();
private String paramPath;
private final Boolean NOT_FILTER = true;
private final Boolean FILTER = false;
/**
* 步骤1-构建参数路径
* 继承自 com.alibaba.fastjson.serializer.PropertyPreFilter
*/
@Override
public boolean apply(JSONSerializer serializer, Object object, String name) {
// 获取当前对象的路径 e.g result.shopInfo
String parentPath = getAndSetObjectPath(serializer.getContext());
// 设置当前对象属性的参数路径 e.g result.shopInfo.picUrl
this.paramPath = parentPath + "." + name;
return NOT_FILTER;
}
/**
* 基于SerialContext构建参数路径
*/
private String getAndSetObjectPath(SerialContext context) {
// 生成参数路径
generateObjectPath(context, new StringBuilder());
return objectPathMap.get(context.object);
}
private void generateObjectPath(SerialContext context, StringBuilder sb) {
if (objectPathMap.containsKey(context.object)) {
sb.append(objectPathMap.get(context.object));
return;
}
// 递归查找父节点路径
generateObjectPath(context.parent, sb);
// 设置当前节点路径
sb.append(".").append(context.fieldName);
objectPathMap.put(context.object, sb.toString());
}
/**
* 步骤2-执行参数过滤
* 继承自com.alibaba.fastjson.serializer.PropertyFilter
*/
@Override
public boolean apply(Object object, String name, Object value) {
// 根据参数路径查询参数配置
Object paramConfig = getParamConfig(this.paramPath);
return Objects.isNull(paramConfig) ? FILTER : NOT_FILTER;
}
/**
* 步骤3-处理参数数据
* 继承自com.alibaba.fastjson.serializer.ValueFilter
*/
@Override
public Object process(Object object, String name, Object value) {
Object paramConfig = getParamConfig(this.paramPath);
return value;
}
} 而fastjson2中PropertyPreFilter,无法通过JSONWriter提供信息来构建路径 public interface PropertyPreFilter extends Filter {
boolean process(JSONWriter writer, Object source, String name);
} 辛苦大佬帮忙看看解法 |
对于问题2 public interface PropertyFilter extends Filter {
boolean apply(Object object, String name, Object value);
} 但是对于存在集合的情况行不通 比如: {"result":{"shopInfoList":[{"name":"名称","url":"xxxx"}]}} 1.当回调apply方法,value是shopInfoList时
2.下一次回调apply方法,object就是集合第一个元素,object的父对象是谁不得而知
@wenshao 麻烦帮忙看看fastjson2中有什么办法能够支持构建参数路径?或者能像fastjson的SerialContext一样存储对象间的父子关系 |
https://oss.sonatype.org/content/repositories/snapshots/com/alibaba/fastjson2/fastjson2/2.0.51-SNAPSHOT/ @Test
public void test() {
Bean bean = new Bean();
bean.item0 = new Item(101);
bean.item1 = new Item(102);
bean.item2 = new Item(103);
FilterDemo filter = new FilterDemo();
String json = JSON.toJSONString(bean, filter, JSONWriter.Feature.ReferenceDetection);
assertEquals("{\"item0\":{\"id\":101},\"item1\":{\"id\":102},\"item2\":{}}", json);
}
public static class FilterDemo
implements PropertyPreFilter {
@Override
public boolean process(JSONWriter writer, Object source, String name) {
String parentPath = writer.getPath();
if (parentPath.startsWith("$.item2")) {
return false;
}
return true;
}
}
public static class Bean {
public Item item0;
public Item item1;
public Item item2;
}
public static class Item {
public int id;
public Item() {
}
public Item(int id) {
this.id = id;
}
}
`` |
Map和非List集合里面的元素getPath不太符合预期 private Bean bean;
@Before
public void setUp() {
bean = new Bean();
bean.item1 = new Item(101);
bean.item2 = new Item(102);
bean.set1 = new HashSet<Item>(){{add(new Item(201));}};
bean.map1 = new HashMap<String, Item>(){{put("childItem", new Item(301));}};
}
@Test
public void test_map1_childItem() {
FilterDemo filter = new FilterDemo("$.map1.childItem");
String json = JSON.toJSONString(bean, filter, JSONWriter.Feature.ReferenceDetection);
org.junit.Assert.assertEquals("{\"item1\":{\"id\":101},\"item2\":{\"id\":102},\"map1\":{},\"set1\":[{\"id\":201}]}"
, json);
}
@Test
public void test_set1_0() {
FilterDemo filter = new FilterDemo("$.set1[0]");
String json = JSON.toJSONString(bean, filter, JSONWriter.Feature.ReferenceDetection);
org.junit.Assert.assertEquals("{\"item1\":{\"id\":101},\"item2\":{\"id\":102},\"map1\":{\"childItem\":{\"id\":301}},\"set1\":[{}]}"
, json);
}
public static class FilterDemo implements PropertyPreFilter {
private final String filterPath;
public FilterDemo(String filterPath) {
this.filterPath = filterPath;
}
@Override
public boolean process(JSONWriter writer, Object source, String name) {
String parentPath = writer.getPath();
if (filterPath != null && parentPath.startsWith(filterPath)) {
return false;
}
return true;
}
}
public static class Bean {
public Item item1;
public Item item2;
public Set<Item> set1;
public Map<String, Item> map1;
}
public static class Item {
public int id;
public Item() {
}
public Item(int id) {
this.id = id;
}
} |
这个时候,还没对Property求值,path是参数source对象的path,process方法有参数 name。 |
fastjson,打印serializer.getContext().getPath()路径
fastjson2,打印writer.getPath()路径
fastjson2的测试方法 @Test
public void test_map1_childItem() {
Bean bean = new Bean();
bean.map1 = new HashMap<String, Item>() {{put("childItem", new Item(301));}};
List<String> paths = new ArrayList<>();
FilterDemo filter = new FilterDemo(paths);
JSON.toJSONString(bean, filter, JSONWriter.Feature.ReferenceDetection);
org.junit.Assert.assertTrue(paths.contains("$.map1.childItem"));
}
public static class FilterDemo implements PropertyPreFilter {
private final List<String> paths;
public FilterDemo(List<String> paths) {
this.paths = paths;
}
@Override
public boolean process(JSONWriter writer, Object source, String name) {
paths.add(writer.getPath());
return true;
}
}
public static class Bean {
public Map<String, Item> map1;
}
public static class Item {
public int id;
public Item() {
}
public Item(int id) {
this.id = id;
}
} 可能原因分析
|
@wenshao 上面这个麻烦再帮忙看看 |
https://oss.sonatype.org/content/repositories/snapshots/com/alibaba/fastjson2/fastjson2/2.0.51-SNAPSHOT/ |
还是不太对,当前fastjson2输出 $
$.map1.childItem
$.map1.childItem fastjson输出
修正代码在ObjectWriterImplMap遍历map1过程中更新path,会导致process()的source是map1,但path已经指向childItem // com.alibaba.fastjson2.writer.ObjectWriterImplMap#writeWithFilter
for (Map.Entry entry : (Iterable<Map.Entry>) map.entrySet()) {
Object value = entry.getValue();
if (value == null && !writeNulls) {
continue;
}
Object entryKey = entry.getKey();
String key;
if (entryKey == null) {
key = null;
} else {
key = entryKey.toString();
}
String refPath = null;
if (refDetect) {
// 1、这里将path指向childItem($.map1.childItem)
refPath = jsonWriter.setPath(key, value);
if (refPath != null) {
jsonWriter.writeName(key);
jsonWriter.writeReference(refPath);
jsonWriter.popPath(value);
continue;
}
}
try {
if (propertyPreFilter != null) {
// 2、这里的object是map1 , key是childItem
// 按照"path是参数source对象的path", 期望$.map1 实际$.map1.childItem
if (!propertyPreFilter.process(jsonWriter, object, key)) {
continue;
}
}
// 省略...
if (value == null) {
jsonWriter.writeNull();
} else {
Class<?> valueType = value.getClass();
ObjectWriter valueWriter = jsonWriter.getObjectWriter(valueType);
// 3、是否可以在valueWriter.write()方法里面去更新path?
valueWriter.write(jsonWriter, value, fieldName, fieldType, this.features);
}
} finally {
if (refDetect) {
jsonWriter.popPath(value);
}
}
} |
请描述您的需求或者改进建议
最近在做fastjson升级到fastjson2改造,由于是网关应用需要对JSON数据进行修改和裁剪,所以会大量用到SerializeFilter扩展能力,在升级到fastjson2的FIlter时,发现以下功能是不兼容的:
请描述你建议的实现方案
1.如果两个filter功能不是互斥,是否可以考虑使用不同方法名
2.JSONWriter的refs提供一个get方法获取Path, Path再提供获取parent和name的get方法,这种是否可行的吗?
描述您考虑过的替代方案
1.目前是通过两个类来分别继承两个接口,然后两个类再互相绑定用于交换数据
附加信息
The text was updated successfully, but these errors were encountered: