2013-07-12 123 views
3

我使用JSON从杰克逊序列化问题,如何从Collections.unmodifiableMap?杰克逊序列化Collections.unmodifiable *

我得到的错误序列是:

com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of java.util.Collections$UnmodifiableMap, problem: No default constructor found 

我想用SimpleAbstractTypeResolver从然而http://wiki.fasterxml.com/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), "[email protected]"); 
testAccount.setMemberEmails(emailMap); 

marshalled = mapper.writeValueAsString(testAccount); 
System.out.println(marshalled); 
Account returnedAccount = mapper.readValue(marshalled, Account.class); 
System.out.println(returnedAccount.containsValue("[email protected]")); 


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); 
    } 

任何想法?提前致谢。

回答

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": "[email protected]", 
     "@class": "java.util.HashMap" 
    } 
} 

这将正确地反序列化。

+0

感谢感知。这完全符合我的目的。是否有一种方法可以在模型类本身没有回退注释的情况下具有相同的行为? – hartraft

+0

@hartraft您可能想要使用的是Jackson Mix In的http://wiki.fasterxml.com/JacksonMixInAnnotations – leo

0

Jackson默认查找默认构造函数。您需要指定@JsonCreator,@JsonProperty注释以使非空构造函数可以工作。

由于您无法将这些注释添加到Collections.UnmodifiableCollection中,因此您无法反序列化它。

  1. 你可能并不需要使用修改的Collection被序列化。有什么意义?反序列化对象时可以这样做。另外,反序列化的对象将与一个序列化的(复制)不同

  2. 如果您真的需要这样做,您可以简单编写自己的UnmodifiableCollection类。这是非常简单的,因为它只是一个底层集合

    public boolean isEmpty() { return c.isEmpty(); } // c is underlying collection 
    

    收集和委托方法调用的包装,除了修改方法:

    public boolean add(E e) { 
        throw new UnsupportedOperationException(); 
    } 
    ..... 
    
  3. 你也可以调用的方法之一之前序列化来序列化数组。当反序列化建立你的模型对象与创建从阵列收集和吸气剂返回不可修改的集合来访问这个集合:

    public Object[] toArray(); 
    public <T> T[] toArray(T[] a); 
    
  4. 您可以在模型中添加@JsonIgnore到您的getter方法,并添加@JsonValue您memberEmails领域。

  5. 您可以创建另一次吸气(私人和不同的名称),其标注为JsonValue为您现场

+0

adited回答您的更新情况 – Tala

+0

塔拉谢谢!我看着我投入了原来的问题的例子,这确实是不必须序列化unmodifiableMap 的ObjectMapper我有使用DefaultTyping这是造成我的问题一个问题。我已经更新了问题,我可以进一步缩小我的搜索标准,现在有点 – hartraft

+0

我添加选项4和5。我会亲自去与4 – Tala