Jersey serialization/deserialization issue: abstract types can only be instantiated with additional type information

淺唱寂寞╮ 提交于 2019-12-12 10:43:56

问题


I'm using jersey for both serialization and deserialization. I've made REST channel on WebLogic using jersey. I have result object with contains abstract class. Jersey adds to the result metadata with this class'es implementation name:

{"order":{"@type":"installationOrder",

However, the same jersey, when using to deserialize this data, is screaming the following:

Caused by: org.codehaus.jackson.map.JsonMappingException: Can not construct instance of ocl.mobile.service.data.order.DetailedOrder, problem: abstract types can only be instantiated with additional type information
 at [Source: sun.net.www.protocol.http.HttpURLConnection$HttpInputStream@97eded; line: 1, column: 2] (through reference chain: ocl.mobile.service.OrderDetailsResult["order"])
    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:252)
    at org.codehaus.jackson.map.deser.SettableBeanProperty$MethodProperty.deserializeAndSet(SettableBeanProperty.java:356)
    at org.codehaus.jackson.map.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:494)
    at org.codehaus.jackson.map.deser.BeanDeserializer.deserialize(BeanDeserializer.java:350)
    at org.codehaus.jackson.map.ObjectMapper._readValue(ObjectMapper.java:2376)
    at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1166)
    at org.codehaus.jackson.jaxrs.JacksonJsonProvider.readFrom(JacksonJsonProvider.java:410)
    at com.sun.jersey.json.impl.provider.entity.JacksonProviderProxy.readFrom(JacksonProviderProxy.java:139)
    at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:553)
    ... 5 more

but he himself have provided this additional information in the JSON he has serialized.

So, how to make jersey to read and understand this "@type" annotations he have created?

This is how I'm using jersey to read data from channel:

private static Client client;

private static void initClient() {
    if (client == null) {
        ClientConfig clientConfig = new DefaultClientConfig();
        clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING,
                Boolean.TRUE);
        client = Client.create(clientConfig);
    }
}

private static <T> T jsonForResult(String addr, Class<T> expectedClass) {
    initClient();
    WebResource r = client.resource(addr);
    try {
        T result = r.get(expectedClass);
    return result;
        } catch (UniformInterfaceException e) {
        log.error(e.getMessage(), e);
        return null;
    }
}

The expectedClass is in my case the class of result, which contains status and the abstract class "order", which has implementations such as "installationOrder".


回答1:


Jersey (or more specifically, Jackson JSON lib it uses with POJO mapping) does not add @type unless type information inclusion is enabled, usually by adding @JsonTypeInfo on an abstract type. So something must have enabled this. Maybe you can share definition DetailOrder class?

As to problem itself: this is usually caused by incompatible types used -- type used for deserialization (reading JSON value into POJO) must be such that @JsonTypeInfo annotation is visible. You can not, for example, just ask for value of type java.lang.Object, since it does not have such annotation. Without knowing actual class definitions it is not possible to point to specific cause, but this is the most likely explanation.




回答2:


try this it works

@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = ExchangeFormat.class, name = "ExchangeFormat"),
@JsonSubTypes.Type(value = TypeStatus.class, name = "TypeStatus"),
})
public abstract class MapperJsonXml <T>

it's the same with xml

@XmlSeeAlso({ExchangeFormat.class,TypeStatus.class})



回答3:


If you just want to just exclude type field, annotate the superclass @XmlTransient, as mentioned here: http://blog.bdoughan.com/2011/06/ignoring-inheritance-with-xmltransient.html

That will make the serialization work as if the superclass fields were in the child class - thus as if there was no inheritance, in which case the type field won't be produced.



来源:https://stackoverflow.com/questions/9066288/jersey-serialization-deserialization-issue-abstract-types-can-only-be-instantia

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!