Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jackson serializing Collections.unmodifiable*

I have a problem using the Jackson serialization from json, how do I serialize from Collections.unmodifiableMap?

The error I get is:

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

I wanted to use the SimpleAbstractTypeResolver from http://wiki.fasterxml.com/SimpleAbstractTypeResolver however I cannot get the inner class type 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);
  }

Any ideas? Thanks in advance.

like image 983
hartraft Avatar asked Jul 12 '13 09:07

hartraft


People also ask

What is Unmodifiable collection?

Collections that do not support modification operations (such as add , remove and clear ) are referred to as unmodifiable. Collections that are not unmodifiable are modifiable. Collections that additionally guarantee that no change in the Collection object will be visible are referred to as immutable.

What is an unmodifiable list?

List<E>. unmodifiable constructor Null safety The Iterator of elements provides the order of the elements. An unmodifiable list cannot have its length or elements changed. If the elements are themselves immutable, then the resulting list is also immutable.

How does Jackson Deserialization work?

Jackson uses default (no argument) constructor to create object and then sets value using setters. so you only need @NoArgsConstructor and @Setter. Save this answer.


1 Answers

Okay, you've run into an edge-ish type case with Jackson. The problem really is that the library will happily use your getter method to retrieve collection and map properties, and only falls back to instantiating these collections/maps if those getter methods return null.

This can fixed by a combination of @JsonProperty/@JsonIgnore annotations, with the caveat that the @class property in your JSON output will change.

Code example:

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

If you serialize this class with your test code you will get the following JSON:

{
    "@class": "misc.stack.pojo.Account",
    "memberEmails": {
        "10": "[email protected]",
        "@class": "java.util.HashMap"
    }
}

Which will deserialize correctly.

like image 107
Perception Avatar answered Oct 05 '22 13:10

Perception