8

我在使用来自 json 的 Jackson 序列化时遇到问题,如何从Collections.unmodifiableMap?

我得到的错误是:

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

有任何想法吗?提前致谢。

4

2 回答 2

3

好吧,你遇到了杰克逊的边缘型案例。真正的问题是,库会很乐意使用您的 getter 方法来检索集合和映射属性,并且只有在这些 getter 方法返回 null 时才回退到实例化这些集合/映射。

这可以通过@JsonProperty/@JsonIgnore注释的组合来解决,但需要注意的是@classJSON 输出中的属性会发生变化。

代码示例:

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"
    }
}

这将正确反序列化。

于 2013-07-12T15:15:54.840 回答
0

Jackson 寻找的第一件事是默认构造函数。如果要使用不同的构造函数,则需要在其上指定 add@JsonCreator@JsonProperty在其参数上指定注解。

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

  1. 您可能不需要使用不可修改的集合进行序列化。重点是什么?您可以在反序列化对象时这样做。反序列化的对象也将不同于序列化(副本)的对象

  2. 如果你真的需要它,你可以简单地编写你自己的UnmodifiableCollection类。它非常简单,因为它只是集合的包装器,并将方法调用委托给底层集合

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

    除了修改方法:

    public boolean add(E e) {
        throw new UnsupportedOperationException();
    }
    .....
    
  3. 您也可以在序列化之前调用其中一种方法来序列化数组。在反序列化构建时,您可以通过从数组创建集合来建模对象,并使用 getter 返回不可修改的集合来访问此集合:

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

  5. 您可以创建另一个 getter(私有且具有不同名称)并将其注释@JsonValue为您的字段

于 2013-07-12T10:28:01.313 回答