9

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

ABean entity = svc.findEntity(...);
objectMapper.readerForUpdating(entity).readValue(json);
[...]
svc.save(entity);

ABean 是一种复杂类型,还包含其他对象,例如:

class ABean {
    public BBean b;
    public CBean c;

    public String d;
}

svc.save(...)将保存 bean 和嵌入的对象

出于安全原因,我想过滤掉一些可以由 JSON 字符串更新的属性,但我想动态地执行此操作,以便对于每个 WS(或用户角色),我可以决定阻止更新哪些属性(所以我不能简单地使用杰克逊观点)

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

4

4 回答 4

7

另一种方法是使用 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;
        }
    }

您可以使用以下方法将修改器注册到 ObjectMapper:

BeanDeserializerModifier modifier = new BeanDeserializerModifierForIgnorables(YourType.class, "name");
DeserializerFactory dFactory = BeanDeserializerFactory.instance.withDeserializerModifier(modifier);
ObjectMapper mapper = new ObjectMapper(null, null, new DefaultDeserializationContext.Impl(dFactory));

然后忽略定义的属性。如果您使用 @JsonAnySetter 注解,则可以忽略 updateBuilder 方法。

问候,马丁

于 2013-08-27T18:47:59.737 回答
1

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

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

于 2012-09-06T18:03:46.007 回答
1

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

于 2012-09-06T18:38:56.280 回答
0

我想出的最强大、最快速、最简单的解决方案就是对反序列化得到的 JsonNode 树进行过滤,然后将过滤后的结果传递给 readerForUpdating。像这样的东西:

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);
        }
    }
} 
于 2012-09-25T18:49:33.217 回答