2011-06-14 23 views
17

我在玩傑克遜的例子,並且在使用不可變類和接口進行反序列化時遇到了一些麻煩。傑克遜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(as = AddressImpl.class)的文章,但沒有奏效。所以我很難過。有沒有人得到這個工作,它甚至支持?

如果我在UserImpl類中將Address替換爲AddressImpl,它就像冠軍一樣工作。

+0

這是56行嗎? WOuld有助於確切知道哪些代碼會拋出Ex – 2011-06-14 15:11:43

+0

@亞倫 - 對不起,添加了編輯 - 它位於最後一行static void main – nsfyn55 2011-06-14 15:17:08

+0

我有類似的問題,這個資源可能有所幫助: http://wiki.fasterxml。 com/JacksonPolymorphicDeserialization – will824 2012-07-19 19:30:29

回答

20

以防萬一你沒有看到它,這裏是一個blog entry,討論與不可變對象和傑克遜工作。

但是,您應該一定能夠使用@JsonDeserialize(as=AddressImpl.class);將其添加到Address.java界面(直接或通過使用混合插件),或者將其添加到字段或屬性。有一點需要注意的是,對於反序列化,它必須在您使用的訪問器旁邊;如果你有一個,如果沒有,則在場後面。註解不在訪問者之間共享;所以例如將它添加到'getter'將不起作用。

Jackson 1.8還最終允許註冊抽象到具體類型(參見http://jira.codehaus.org/browse/JACKSON-464瞭解更多細節),這可能是表明'AddressImpl'將被用於'地址'的最佳選項。

+0

嗯讓我試試這個 – nsfyn55 2011-06-14 18:00:55

+2

我們走吧!我將@JsonDeserialize(as = AddressImpl.class)添加到接口中,它像冠軍一樣工作。看起來,將UserImpl類添加到成員之上會更加謹慎,在界面中指定具體的實現看起來好像破壞了目的,即使它是註釋。謝謝你的幫助! – nsfyn55 2011-06-14 18:06:47

+0

是的,將它添加到界面並不美觀;但不幸的是,對面的做法很困難(如果不是不可能的話),因爲無法枚舉JVM加載的所有類(以查找註釋)。此外,您可以考慮通過混合插入(請參閱http://wiki.fasterxml.com/JacksonMixInAnnotations)添加註釋,或者添加到帶有地址的構造函數參數中;應該可以將它添加到@JsonProperty旁邊 – StaxMan 2011-06-15 00:24:33