我在使用json的Jackson序列化时遇到问题,如何从Collections.unmodifiableMap?
序列化
我得到的错误是:
com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of java.util.Collections$UnmodifiableMap, problem: No default constructor found
我想使用http://wiki.fasterxml.com/SimpleAbstractTypeResolver中的SimpleAbstractTypeResolver
但是我无法获得内部类类型Collections$UnmodifiableMap
Map<Integer, String> emailMap = newHashMap();
Account testAccount = new Account();
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, As.PROPERTY);
String marshalled ;
emailMap.put(Integer.valueOf(10), "bob@mail.com");
testAccount.setMemberEmails(emailMap);
marshalled = mapper.writeValueAsString(testAccount);
System.out.println(marshalled);
Account returnedAccount = mapper.readValue(marshalled, Account.class);
System.out.println(returnedAccount.containsValue("bob@mail.com"));
public class Account {
private Map<Integer, String> memberEmails = Maps.newHashMap();
public void setMemberEmails(Map<Integer, String> memberEmails) {
this.memberEmails = memberEmails;
}
public Map<Integer, String> getMemberEmails() {
return Collections.unmodifiableMap(memberEmails);
}
有什么想法吗?提前谢谢。
答案 0 :(得分:1)
好吧,你遇到了杰克逊的边缘式案例。问题实际上是库会愉快地使用你的getter方法来检索集合和映射属性,并且只有当这些getter方法返回null时才会回退到实例化这些集合/映射。
这可以通过@JsonProperty/@JsonIgnore
注释的组合来修复,但需要注意的是JSON输出中的@class
属性会发生变化。
代码示例:
public class Account {
@JsonProperty("memberEmails")
private Map<Integer, String> memberEmails = Maps.newHashMap();
public Account() {
super();
}
public void setMemberEmails(Map<Integer, String> memberEmails) {
this.memberEmails = memberEmails;
}
@JsonIgnore
public Map<Integer, String> getMemberEmails() {
return Collections.unmodifiableMap(memberEmails);
}
}
如果使用测试代码序列化此类,您将获得以下JSON:
{
"@class": "misc.stack.pojo.Account",
"memberEmails": {
"10": "bob@mail.com",
"@class": "java.util.HashMap"
}
}
将正确反序列化。
答案 1 :(得分:0)
Jackson默认查找默认构造函数。您需要为非空构造函数指定@JsonCreator,@ JsonProperty注释才能工作。
由于您无法将这些注释添加到Collections.UnmodifiableCollection,因此无法对其进行反序列化。
您可能不需要使用不可修改的集合进行序列化。有什么意义?您可以在反序列化对象时执行此操作。反序列化对象也将与序列化(复制)
如果你确实需要,你可以简单地编写自己的UnmodifiableCollection类。它非常简单,因为它只是集合的包装并将方法调用委托给底层集合
public boolean isEmpty() { return c.isEmpty(); } // c is underlying collection
除了修改方法:
public boolean add(E e) {
throw new UnsupportedOperationException();
}
.....
您还可以在序列化之前调用其中一个方法来序列化数组。在反序列化构建时,您可以使用从数组创建集合来建模对象,并使用getter返回不可修改的集合来访问此集合:
public Object[] toArray();
public <T> T[] toArray(T[] a);
您可以在模型中的getter方法中添加@JsonIgnore
,并将@JsonValue
添加到您的memberEmails字段。
您可以创建另一个getter(私有且具有不同名称)并将其注释为您的字段的JsonValue