【问题标题】:Jackson: ignore unknown enum values杰克逊:忽略未知的枚举值
【发布时间】:2015-05-23 15:57:57
【问题描述】:

我正在尝试反序列化从 RESTful Web 服务获得的 JSON 对象。 我有以下课程:

public class ACE {
    private Persona trustee;
    private String accesstype;
    private final Set<Right> accessrights = EnumSet.noneOf(Right.class);
    private final Set<Inheritance> inherit_flags
            = EnumSet.noneOf(Inheritance.class);
    private String op;

    public static enum Right {
        traverse, list, dir_read_attr, dir_read_ext_attr, add_file, add_subdir,
        dir_write_attr, dir_write_ext_attr, delete_child, std_delete,
        std_read_dac, std_write_dac, std_write_owner,

        dir_gen_all, dir_gen_execute, dir_gen_read, dir_gen_write, modify;
    }

    public static enum Inheritance {
        object_inherit, container_inherit, no_prop_inherit, inherit_only,
        inherited_ace;
    }

    public ACE setAccessrights(Set<Right> rights) {
        accessrights.clear();
        accessrights.addAll(rights);
        return this;
    }
...

现在 webservices 在 set 'accessrights' 中返回 'std_synchronize',这是一个未在 Right 枚举类型中定义的值。

我收到以下异常:

    com.fasterxml.jackson.databind.JsonMappingException: N/A (through reference chain: gina.nas.ws.ACL["acl"]->gina.nas.ws.ACE["accessrights"])
            at com.fasterxml.jackson.databind.deser.SettableBeanProperty._throwAsIOE(SettableBeanProperty.java:421)
            at com.fasterxml.jackson.databind.deser.SettableBeanProperty._throwAsIOE(SettableBeanProperty.java:404)
            at com.fasterxml.jackson.databind.deser.impl.MethodProperty.set(MethodProperty.java:116)
            at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:98)
            at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:308)
            at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:121)
            at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:147)
            at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:18)
            at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:375)
            at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:98)
            at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:308)
            at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:121)
            at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:2793)
            at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:1989)
            at gina.nas.ws.NasSession.getACL(NasSession.java:188)
            at gina.nas.NasAPI.getSecurity(NasAPI.java:451)
            at gina.nas.NasAPI.getSecurity(NasAPI.java:244)
        at gina.nas.NasHelper.setStructureUOACL(NasHelper.java:622)
        at gina.nas.NasHelper.setStructureUOACL(NasHelper.java:263)
        at gina.nas.NasHelper.setStructureUOACL(NasHelper.java:280)
        at gina.nas.NasHelper.setStructureUOACL(NasHelper.java:299)
        at gina.nas.NasHelper.setStructureUOACL(NasHelper.java:317)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at org.mozilla.javascript.MemberBox.invoke(MemberBox.java:126)
        ... 13 more
Caused by: java.lang.NullPointerException
        at java.util.EnumSet.typeCheck(Unknown Source)
        at java.util.RegularEnumSet.add(Unknown Source)
        at java.util.RegularEnumSet.add(Unknown Source)
        at java.util.AbstractCollection.addAll(Unknown Source)
        at java.util.RegularEnumSet.addAll(Unknown Source)
        at gina.nas.ws.ACE.setAccessrights(ACE.java:51)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:97)
        ... 38 more

我在 ObjectMapper 中设置了以下标志:

mapper.configure(
        DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL, true);

但是当杰克逊试图将 null 添加到集合中时,问题似乎出现了。

有没有办法简单地忽略未知值?

【问题讨论】:

  • 在我的测试用例中没有引发异常,所以我猜问题出在 ACE.setAccessrights 方法中。可以发一下吗?
  • @Giovanni 你是对的。我刚刚添加了方法。

标签: java json enums jackson


【解决方案1】:

另一种方法是回退到未知数的默认枚举值。你可以这样做

  1. @JsonEnumDefaultValue注释默认的枚举字段
  2. 在您的 ObjectMapper 上启用 DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE

请参考以下示例:

  1. 枚举变化
public static enum Right { 
      traverse, list, dir_read_attr, dir_read_ext_attr, add_file, 
      add_subdir, dir_write_attr, dir_write_ext_attr, delete_child, std_delete, 
      std_read_dac, std_write_dac, std_write_owner, dir_gen_all, dir_gen_execute, 
      dir_gen_read, dir_gen_write, modify,
      @JsonEnumDefaultValue UNKNOWN; 
}
  1. ObjectMapper 的变化
ObjectMapper().enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE);

【讨论】:

    【解决方案2】:

    我没有设法重现您对 jackson 2.5.1 的问题

    这是我的 ACE 课程

    public class ACE {
        private final Set<Right> accessrights = EnumSet.noneOf(Right.class);
        private final Set<Inheritance> inherit_flags
                = EnumSet.noneOf(Inheritance.class);
    
        public static enum Right {
            traverse, list, dir_read_attr, dir_read_ext_attr, add_file, add_subdir,
            dir_write_attr, dir_write_ext_attr, delete_child, std_delete,
            std_read_dac, std_write_dac, std_write_owner,
            dir_gen_all, dir_gen_execute, dir_gen_read, dir_gen_write, modify;
        }
    
        public static enum Inheritance {
            object_inherit, container_inherit, no_prop_inherit, inherit_only,
            inherited_ace;
        }
    
        public Set<Right> getAccessrights() {
            return accessrights;
        }
    
        public Set<Inheritance> getInherit_flags() {
            return inherit_flags;
        }
    
    }
    

    这是我的测试用例:

    package test;
    
    import test.ACE.Inheritance;
    import test.ACE.Right;
    
    import com.fasterxml.jackson.databind.DeserializationFeature;
    import com.fasterxml.jackson.databind.ObjectMapper;
    
    public class TestJacksonEnum {
    
        public static void main(String[] args) throws Exception {
            // TODO Auto-generated method stub
            ACE ace= new ACE();
            ace.getAccessrights().add(Right.add_file);
            ace.getAccessrights().add(Right.add_subdir);
            ace.getInherit_flags().add(Inheritance.container_inherit);
            ace.getInherit_flags().add(Inheritance.inherit_only);
            ObjectMapper mapper=new ObjectMapper();
            mapper.configure(
                    DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL, true);
            System.out.println(mapper.writeValueAsString(ace));
            String serializedFormREST="{\"accessrights\":[\"std_synchronize\",\"add_subdir\"],\"inherit_flags\":[\"container_inherit\",\"inherit_only\"]}";
            ACE deserializedAce= mapper.readValue(serializedFormREST, ACE.class);
            System.out.println(mapper.writeValueAsString(deserializedAce));
        }
    
    
    }
    

    deserializedAce 对象被正确读取,并且该集合不包含 std_synchronize 但它包含一个空值。我错过了什么吗?

    【讨论】:

    • 你是对的:问题似乎出在 setter 中(我已经添加了 setter 的代码),更准确地说,是 jackson 传递给 setter 的集合。如果我将参数声明为 EnumSet 而不是 Set,它将起作用。
    猜你喜欢
    • 1970-01-01
    • 2016-04-19
    • 2016-01-16
    • 1970-01-01
    • 2018-05-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-11
    • 1970-01-01
    相关资源
    最近更新 更多