Java 反序列化期间属性的Jackson动态筛选

Java 反序列化期间属性的Jackson动态筛选,java,json,filtering,jackson,deserialization,Java,Json,Filtering,Jackson,Deserialization,我有一个REST-WS来更新一个bean对象,它接收一个JSON字符串作为输入 ABean entity = svc.findEntity(...); objectMapper.readerForUpdating(entity).readValue(json); [...] svc.save(entity); ABean是一种复杂类型,还包含其他对象,例如: class ABean { public BBean b; public CBean c; public St

我有一个REST-WS来更新一个bean对象,它接收一个JSON字符串作为输入

ABean entity = svc.findEntity(...);
objectMapper.readerForUpdating(entity).readValue(json);
[...]
svc.save(entity);
ABean是一种复杂类型,还包含其他对象,例如:

class ABean {
    public BBean b;
    public CBean c;

    public String d;
}
save(…)将保存bean和嵌入对象

出于安全原因,我想过滤掉一些可以通过JSON字符串更新的属性,但我想动态地这样做,这样对于每个WS(或用户角色),我就可以决定要防止更新哪些属性(因此我不能简单地使用Jackson视图)


总而言之,在JSON反序列化过程中,有什么方法可以动态过滤掉属性吗?

从您的描述中,我假设您不能简单地使用
@JsonIgnore
注释来防止为每个特定类序列化字段


看看使用:mix-ins允许您用必要的注释替换类定义来进行数据绑定。在序列化过程中,您可以在类定义中选择一个特定的混合来代替正在序列化的实际类。定义一组混合插件来处理每种情况,然后在序列化特定bean时选择合适的组合。

您可以使用@JsonIgnoreType忽略序列化过程中的java类/接口/枚举。此外,您可以使用@JsonIgnoreProperties忽略属性列表,使用@JsonIgnore忽略特定属性

我想到的最强大、最快捷、最简单的解决方案就是过滤从反序列化中获得的JsonNode树,然后将过滤结果传递给读卡器进行更新。诸如此类:

public class JacksonHelper {
    public JsonNode filterBeanTree(JsonNode o, List<String> includedProperties,
            List<String> excludedProperties, int maxDepth) {
        JsonNode tree = o.deepCopy();
        this.filterBeanTreeRecursive(tree, includedProperties, excludedProperties, maxDepth, null);
        return tree;
    }

    private void filterBeanTreeRecursive(JsonNode tree, List<String> includedProperties,
            List<String> excludedProperties, int maxDepth, String key) {
        Iterator<Entry<String, JsonNode>> fieldsIter = tree.fields();
        while (fieldsIter.hasNext()) {
            Entry<String, JsonNode> field = fieldsIter.next();
            String fullName = key == null ? field.getKey() : key + "." + field.getKey();

            boolean depthOk = field.getValue().isContainerNode() && maxDepth >= 0;
            boolean isIncluded = includedProperties != null
                    && !includedProperties.contains(fullName);
            boolean isExcluded = excludedProperties != null
                    && excludedProperties.contains(fullName);
            if ((!depthOk && !isIncluded) || isExcluded) {
                fieldsIter.remove();
                continue;
            }

            this.filterBeanTreeRecursive(field.getValue(), includedProperties, excludedProperties,
                    maxDepth - 1, fullName);
        }
    }
} 
公共类JacksonHelper{
公共JsonNode筛选器Beantree(JsonNode o,列表includedProperties,
列表excludedProperties,int maxDepth){
JsonNode tree=o.deepCopy();
this.filterBeantreerCursive(树,includedProperties,excludedProperties,maxDepth,null);
回归树;
}
私有void过滤器BeantreeCursive(JsonNode树,列表包含属性,
列表excludedProperties、int maxDepth、字符串键){
迭代器fieldsIter=tree.fields();
while(fieldsIter.hasNext()){
输入字段=fieldsIter.next();
字符串fullName=key==null?field.getKey():key+““+field.getKey();
布尔depthOk=field.getValue().isContainerNode()和&maxDepth>=0;
布尔ISinclude=includedProperties!=null
&&!includedProperties.contains(全名);
布尔值IsExclude=excludedProperties!=null
&&excludedProperties.contains(全名);
如果((!depthOk&&!包括在内)| |不包括在内){
fieldsIter.remove();
继续;
}
this.filterBeantReCursive(field.getValue(),includeProperties,excludedProperties,
maxDepth-1,全名);
}
}
} 

另一种方法是使用BeanDeserializerModifier:

private static class BeanDeserializerModifierForIgnorables extends BeanDeserializerModifier {

        private java.lang.Class<?> type;
        private List<String> ignorables;

        public BeanDeserializerModifierForIgnorables(java.lang.Class clazz, String... properties) {
            ignorables = new ArrayList<>();
            for(String property : properties) {
                ignorables.add(property);
            }
            this.type = clazz;
        }

        @Override
        public BeanDeserializerBuilder updateBuilder(
                DeserializationConfig config, BeanDescription beanDesc,
                BeanDeserializerBuilder builder) {
            if(!type.equals(beanDesc.getBeanClass())) {
                return builder;
            }

            for(String ignorable : ignorables) {
                builder.addIgnorable(ignorable);                
            }

            return builder;
        }

        @Override
        public List<BeanPropertyDefinition> updateProperties(
                DeserializationConfig config, BeanDescription beanDesc,
                List<BeanPropertyDefinition> propDefs) {
            if(!type.equals(beanDesc.getBeanClass())) {
                return propDefs;
            }

            List<BeanPropertyDefinition> newPropDefs = new ArrayList<>();
            for(BeanPropertyDefinition propDef : propDefs) {
                if(!ignorables.contains(propDef.getName())) {
                    newPropDefs.add(propDef);
                }
            }
            return newPropDefs;
        }
    }
然后忽略定义的属性。如果使用@JsonAnySetter注释,则可以忽略updateBuilder方法

您好,
Martin

这仅对静态(编译时)过滤器有效。我认为这与使用视图所能获得的功能相同。如果我从数据库中提取了一组动态角色及其权限,并希望根据这些规则进行筛选,该怎么办?谢谢!我遇到了与原始海报相同的问题,并且相信这应该是公认的答案,因为它支持基于类类型选择性地删除属性。如何向Jersey注册修改器?
BeanDeserializerModifier modifier = new BeanDeserializerModifierForIgnorables(YourType.class, "name");
DeserializerFactory dFactory = BeanDeserializerFactory.instance.withDeserializerModifier(modifier);
ObjectMapper mapper = new ObjectMapper(null, null, new DefaultDeserializationContext.Impl(dFactory));