杰克逊:忽略未知的枚举值
Jackson: ignore unknown enum values
我正在尝试反序列化从 RESTful 网络服务获得的 JSON 对象。
我有以下 class:
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;
}
...
现在网络服务returns 'std_synchronize'在集合'accessrights'中,这是一个没有在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);
但是当 jackson 试图将 null 添加到集合中时,问题似乎出现了。
有没有办法简单地忽略未知值?
我没能用 jackson 2.5.1 重现你的问题
这是我的王牌class
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));
}
}
反序列化的Ace对象被正确读取并且该集合不包含std_synchronize但它包含一个空值。我错过了什么吗?
另一种方法是回退到未知数的默认枚举值。你可以通过
- 注释应使用
@JsonEnumDefaultValue
默认的枚举字段
和
- 在您的
ObjectMapper
上启用 DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE
。
参考下面的例子:
- 枚举的变化
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;
}
- ObjectMapper 的变化
ObjectMapper().enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE);
我正在尝试反序列化从 RESTful 网络服务获得的 JSON 对象。 我有以下 class:
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;
}
...
现在网络服务returns 'std_synchronize'在集合'accessrights'中,这是一个没有在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);
但是当 jackson 试图将 null 添加到集合中时,问题似乎出现了。
有没有办法简单地忽略未知值?
我没能用 jackson 2.5.1 重现你的问题
这是我的王牌class
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));
}
}
反序列化的Ace对象被正确读取并且该集合不包含std_synchronize但它包含一个空值。我错过了什么吗?
另一种方法是回退到未知数的默认枚举值。你可以通过
- 注释应使用
@JsonEnumDefaultValue
默认的枚举字段 和 - 在您的
ObjectMapper
上启用DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE
。
参考下面的例子:
- 枚举的变化
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;
}
- ObjectMapper 的变化
ObjectMapper().enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE);