Jackson Dynamic filtering of properties during deserialization

后端 未结 4 456
梦毁少年i
梦毁少年i 2020-12-10 06:06

I have a REST WS to update a bean object which receives a JSON string as input.

ABean entity = svc.findEntity(...);
objectMapper.readerForUpdating(entity).r         


        
相关标签:
4条回答
  • 2020-12-10 06:30

    Another way is using 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;
            }
        }
    

    You can register the modfier to the ObjectMapper with:

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

    Then the defined properties are ignored. You can ignore the updateBuilder method if you use the @JsonAnySetter annotation.

    Greetings, Martin

    0 讨论(0)
  • 2020-12-10 06:31

    You can use @JsonIgnoreType to ignore a java class/interface/enum from serializing. Additionally you can use @JsonIgnoreProperties for ignoring a list of properties and @JsonIgnore for a specific property

    0 讨论(0)
  • 2020-12-10 06:37

    I assume from your description that you can't simply use the @JsonIgnore annotation to prevent the fields from being serialized for each particular class.

    Look at using Jakson mix-ins: mix-ins allow you to substitute a class definition - with the necessary annotations - for data binding. During serialization you can choose a particular mix-in class definition to stand in for the actual class being serialized. Define a set of mix-ins to handle every case, then choose which is appropriate when you serialize a particular bean.

    0 讨论(0)
  • 2020-12-10 06:39

    The most powerful, quick and easy solution I came up with is just filtering the JsonNode tree obtained from the deserialization, then pass the filtered result to the readerForUpdating. Something like that:

    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);
            }
        }
    } 
    
    0 讨论(0)
提交回复
热议问题