2011-06-14 7 views
17

저는 Jackson 예제를 가지고 놀고 있으며, 변환 할 수없는 클래스와 인터페이스를 사용하여 직렬화를 해제하는 데 문제가 있습니다.Jackson JSON, 변경 불가능한 클래스 및 인터페이스

package com.art.starter.jackson_starter; 

import java.io.IOException; 
import java.io.StringReader; 
import java.io.StringWriter; 

import org.codehaus.jackson.JsonGenerationException; 
import org.codehaus.jackson.map.JsonMappingException; 
import org.codehaus.jackson.map.ObjectMapper; 
/** * Hello world! * */ public class App { 
    public static void main(String[] args) throws JsonGenerationException, JsonMappingException, IOException 
    { 
     System.out.println("Hello World!"); 

     AddressImpl.AddressBuilder builder = new AddressImpl.AddressBuilder(); 
     NameImpl.Builder nameBuilder = new NameImpl.Builder(); 
     UserImpl.Builder userBuilder = new UserImpl.Builder(); 


     Name name = nameBuilder.first("FirstName") 
        .last("LastName") 
        .build(); 

     Address address = builder.setCity("TestCity") 
       .setCountry("TestCountry") 
       .setState("PA") 
       .setStreet("TestAddress") 
       .setZip(123) 
       .build();  

     User user = userBuilder.address(address) 
       .gender(User.Gender.MALE) 
       .isVerified(true) 
       .userImage(new byte[5]) 
       .build(); 

     System.out.println(address);   
     System.out.println(name); 
     System.out.println(user); 

     StringWriter sw = new StringWriter(); 
     ObjectMapper mapper = new ObjectMapper(); 
     mapper.writeValue(sw, user); 
     System.out.println(sw); 


     StringReader sr = new StringReader("{\"address\":{\"state\":\"PA\",\"country\":\"TestCountry\",\"street\":\"TestAddress\",\"city\":\"TestCity\",\"zip\":123},\"verified\":true,\"gender\":\"MALE\",\"userImage\":\"AAAAAAA=\"}"); 

     /* 
      This line throws the Exception   
     */ 
     User user2 = mapper.readValue(sr, UserImpl.class); 

     System.out.println(user2); 
    } } 

package com.art.starter.jackson_starter; 

import java.util.Arrays; 

import org.codehaus.jackson.annotate.JsonCreator; 
import org.codehaus.jackson.annotate.JsonProperty; 

public final class UserImpl implements User 
{ 
    private final Address address; 
    private final Gender gender; 
    private final byte[] userImage; 
    private final boolean isVerified; 

    public static class Builder 
    { 
     private Address address; 
     private Gender gender; 
     //  private Name name; 
     private byte[] userImage; 
     private boolean isVerified; 

     public Builder address(Address address) 
     { 
     this.address = address; 
     return this; 
     } 

     public Builder gender(Gender gender) 
     { 
     this.gender = gender; 
     return this; 
     } 

     //  public Builder name(Name name) 
     //  { 
     //   this.name = name; 
     //   return this; 
     //  } 

     public Builder userImage(byte[] userImage) 
     { 
     this.userImage = userImage; 
     return this; 
     } 

     public Builder isVerified(boolean isVerified) 
     { 
     this.isVerified = isVerified; 
     return this; 
     } 

     public UserImpl build() 
     { 
     return new UserImpl(address, gender, userImage, isVerified); 
     } 
    } 

    @JsonCreator 
    public UserImpl(@JsonProperty("address") Address address, @JsonProperty("gender") Gender gender, @JsonProperty("userImage") byte[] userImage, 
     @JsonProperty("verified") boolean isVerified) 
    { 
     super(); 
     this.address = address; 
     this.gender = gender; 
     this.userImage = userImage; 
     this.isVerified = isVerified; 
    } 

    public Address getAddress() 
    { 
     return address; 
    } 

    public Gender getGender() 
    { 
     return gender; 
     } 

    public byte[] getUserImage() 
    { 
     return userImage; 
    } 

    public boolean isVerified() 
    { 
     return isVerified; 
    } 

    @Override 
    public String toString() 
    { 
     StringBuilder builder2 = new StringBuilder(); 
     builder2.append("UserImpl [address="); 
     builder2.append(address); 
     builder2.append(", gender="); 
     builder2.append(gender); 
     builder2.append(", isVerified="); 
     builder2.append(isVerified); 
     builder2.append(", name="); 
     builder2.append(", userImage="); 
     builder2.append(Arrays.toString(userImage)); 
     builder2.append("]"); 
     return builder2.toString(); 
    } 

} 

package com.art.starter.jackson_starter; 

import org.codehaus.jackson.annotate.JsonCreator; 
import org.codehaus.jackson.annotate.JsonProperty; 

public final class AddressImpl implements Address 
{ 
    private final String city; 
    private final String country; 
    private final String street; 
    private final String state; 
    private final int zip; 

    public static class AddressBuilder 
    { 
     private String city; 
     private String country; 
     private String street; 
     private String state; 
     private int zip; 

     public AddressBuilder setCity(String city) 
     { 
     this.city = city; 
     return this; 
     } 

     public AddressBuilder setCountry(String country) 
     { 
     this.country = country; 
     return this; 
     } 

     public AddressBuilder setStreet(String street) 
     { 
     this.street = street; 
     return this; 
     } 

     public AddressBuilder setState(String state) 
     { 
     this.state = state; 
     return this; 
     } 

     public AddressBuilder setZip(int zip) 
     { 
     this.zip = zip; 
     return this; 
     } 

     public AddressImpl build() 
     { 
     return new AddressImpl(city, country, street, state, zip); 
     } 

    } 

    @JsonCreator 
    public AddressImpl(@JsonProperty("city") String city, @JsonProperty("country") String country, @JsonProperty("street") String street, 
     @JsonProperty("state") String state, @JsonProperty("zip") int zip) 
    { 
     this.city = city; 
     this.country = country; 
     this.street = street; 
     this.state = state; 
     this.zip = zip; 
    } 

    public String getCity() 
    { 
     return city; 
    } 

    public String getCountry() 
    { 
     return country; 
    } 

    public String getStreet() 
    { 
     return street; 
    } 

    public String getState() 
    { 
     return state; 
    } 

    public int getZip() 
    { 
     return zip; 
    } 

    @Override 
    public String toString() 
    { 
     StringBuilder builder = new StringBuilder(); 
     builder.append("AddressImpl [city="); 
     builder.append(city); 
     builder.append(", country="); 
     builder.append(country); 
     builder.append(", state="); 
     builder.append(state); 
     builder.append(", street="); 
     builder.append(street); 
     builder.append(", zip="); 
     builder.append(zip); 
     builder.append("]"); 
     return builder.toString(); 
    } 

} 

문제는 주소와 함께 나타납니다 :

다음은 내 코드입니다.

Exception in thread "main" org.codehaus.jackson.map.JsonMappingException: Can not construct instance of com.art.starter.jackson_starter.Address, problem: abstract types can only be instantiated with additional type information 
at [Source: [email protected]; line: 1, column: 2] 
    at org.codehaus.jackson.map.JsonMappingException.from(JsonMappingException.java:163) 
    at org.codehaus.jackson.map.deser.StdDeserializationContext.instantiationException(StdDeserializationContext.java:212) 
    at org.codehaus.jackson.map.deser.AbstractDeserializer.deserialize(AbstractDeserializer.java:97) 
    at org.codehaus.jackson.map.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:230) 
    at org.codehaus.jackson.map.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:595) 
    at org.codehaus.jackson.map.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:472) 
    at org.codehaus.jackson.map.deser.BeanDeserializer.deserialize(BeanDeserializer.java:350) 
    at org.codehaus.jackson.map.ObjectMapper._readMapAndClose(ObjectMapper.java:2391) 
    at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1614) 
    at com.art.starter.jackson_starter.App.main(App.java:56) 

나는 잭슨은 구체적인 구현 AddressImpl에 대한 인터페이스가 주소를 해결하기위한 방법이 없기 때문입니다 확신 :이 예외를 얻을. 나는 문서를 훑어 보았고 @JsonDeserialize (AddressImpl.class 같은)에 관한 몇 가지 기사를 살펴 봤지만 작동하지 않았다. 그래서 나는 혼란 스럽다. 아무도 이것이 작동하도록 얻었습니까? 심지어 지원됩니까?

Address을 클래스의 AddressImpl으로 바꾼다면 챔피언처럼 작동합니다.

+0

정확히 56 행입니까? WOuld가 정확히 어떤 코드가 던져 넣었는지 알 수 있습니다. Ex –

+0

@ Aaron-sorry 덧붙여 수정 된 내용 - static void main의 마지막 줄 다음에 – nsfyn55

+0

비슷한 리소스가 있습니다. http : //wiki.fasterxml. co.kr/JacksonPolymorphicDeserialization – will824

답변

20

만약 당신이 그것을 보지 못했다면, 다음은 불변의 객체와 Jackson을 다루는 것을 다루는 blog entry입니다.

@JsonDeserialize(as=AddressImpl.class);을 Address.java 인터페이스에 직접 추가하거나 (mix-ins을 사용하여) 추가하거나 필드 또는 속성에 추가하여 사용할 수 있어야합니다. 한 가지주의해야 할 점은 deserialization을 위해서는 사용하는 접근 자 옆에 반드시 있어야한다는 것입니다. 세터가 있다면, 필드 옆에 하나가 있으면 그렇지 않습니다. 어노테이션은 접근 자간에 (아직) 공유되지 않습니다. 예를 들어 'getter'에 추가하면 작동하지 않습니다.

잭슨 1.8은 또한 'AddressImpl'이 '주소'로 사용됨을 나타내는 최상의 옵션 일 수있는 추상 - 콘크리트 유형 (자세한 내용은 http://jira.codehaus.org/browse/JACKSON-464 참조)의 등록을 마침내 허용합니다.

+0

흠 나는 이것을 시도하겠습니다. – nsfyn55

+2

저기 우리가 간다! 인터페이스에 @JsonDeserialize (= AddressImpl.class로)를 추가하고 챔피언처럼 작업했습니다. 이것이 UserImpl 클래스의 멤버 위에 추가되는 것이 훨씬 더 신중한 것처럼 보이며, 인터페이스에서 구체적인 구현을 지정하면 주석이더라도 목적을 무력화하는 것처럼 보입니다. 당신의 도움을 주셔서 감사합니다! – nsfyn55

+0

예, 인터페이스에 추가하는 것이 좋지 않습니다. 불행하게도 반대는 JVM이로드 한 모든 클래스 (주석을 찾기 위해)를 열거 할 방법이 없으므로 (불가능하지는 않지만) 어렵습니다. 또한, 믹스 인 (http://wiki.fasterxml.com/JacksonMixInAnnotations 참조)을 통해 주석을 추가하거나 Address를 사용하는 생성자 매개 변수에 주석을 추가 할 수도 있습니다. @JsonProperty 옆에 그것을 추가 할 수 있어야합니다 – StaxMan

관련 문제