jacksonJSON,不可变类和接口

我正在使用Jackson示例,并且在使用不可变类和接口进行反序列化时遇到一些麻烦。

以下是我的代码:

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: java.io.StringReader@785f8172; 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) 

我确信这是因为jackson无法解析Address这是一个具体实现的AddressImpl的接口。 我一直在浏览文档并查看了一些关于@JsonDeserialize(as = AddressImpl.class)的文章,但它没有用。 所以我很难过。 有没有人得到这个工作,它甚至支持?

如果我在UserImpl类中用AddressImpl替换Address ,它就像一个冠军。

如果您还没有看到它,这里有一篇博客文章 ,讨论使用不可变对象和jackson。

但你绝对应该能够使用@JsonDeserialize(as=AddressImpl.class); 通过将其添加到Address.java接口(直接或通过使用混合),或将其添加到字段或属性。 需要注意的一点是,对于反序列化,它必须位于您使用的访问器旁边; setter如果你有一个,如果没有,在field旁边。 访问者之间尚未共享注释; 所以例如将它添加到’getter’是行不通的。

Jackson 1.8最终还允许注册抽象到具体的类型(更多细节请参见http://jira.codehaus.org/browse/JACKSON-464 ),这可能是表明要使用’AddressImpl’的最佳选择为’地址’。