2013-07-12 2 views
3

내가 어떻게 Collections.unmodifiableMap?잭슨 직렬화 Collections.unmodifiable *

내가 오류에서 직렬화 않는, JSON에서 잭슨 직렬화 사용에 문제가있다 :

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

자에 대한 JsonValue로 주석을 달 수는, 당신은 잭슨 가장자리 틱 타입의 케이스에 실행했습니다. 문제는 실제로 라이브러리가 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. 아마도 수정이 불가능한 컬렉션을 직렬화 할 필요는 없습니다. 요점이 뭐야? 객체를 비 직렬화 할 때 그렇게 할 수 있습니다. 또한 비 직렬화 된 객체는 직렬화 된 객체와 다를 수 있습니다. (복사)

  2. 정말 필요한 경우 자신의 UnmodifiableCollection 클래스를 작성할 수 있습니다.

    public boolean add(E e) { 
        throw new UnsupportedOperationException(); 
    } 
    ..... 
    
  3. 또한 이전 방법 중 하나를 호출 할 수는 수정 방법을 제외하고는 기본 수집

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

    에 대한 수집 및 위임 방법 호출 단지 래퍼이기 때문에 그것은 매우 간단합니다 배열을 직렬화하기위한 직렬화.

    public Object[] toArray(); 
    public <T> T[] toArray(T[] a); 
    
  4. 당신은 모델에 getter 메소드에 @JsonIgnore를 추가하고 memberEmails 필드에 @JsonValue을 추가 할 수 있습니다 : 배열에서 모음을 만드는 당신에게 모델 객체를 구축하고 게터 반환 변경 불가능한 컬렉션이 컬렉션에 액세스 직렬화를 해제합니다.

  5. 있습니다 (개인 및 다른 이름으로) 다른 게터를 만들고 필드

+0

업데이트 된 케이스에 대한 답변이 – Tala

+0

감사합니다. 내가 원래의 질문에 넣은 예를 들여다. 그리고 실제로이 문제는 unmodifiableMap을 serialize하는 것이 없다. ObjectMapper는 내 문제를 일으키는 DefaultTyping을 사용하고있다. 나는 질문을 업데이트했고 검색 기준을 더 좁힐 수 있습니다. – hartraft

+0

옵션 4와 5를 추가했습니다. 개인적으로 4 – Tala