Net_Hans
Net_Hans

Reputation: 185

Java jax-rs client response entity generic

I have a problem with a generic function. I want to use a function to which I assign a certain class / type to first generate the corresponding result from a rest response and then return it.

public class TimerService {

    [...]

    public <T extends myObjInterface> RestMessageContainer<T> send(String endpointPath, Map<String, String> parameters, Class<T> clazz) {
        [...]
        Response response = webTarget.request(MediaType.APPLICATION_JSON_TYPE).get();
        RestMessageContainer<T> container = response.readEntity(new GenericType<RestMessageContainer<T>>() {});
        return container;
    }
}

public class RestMessageContainer<T extends myObjInterface> {

    [...]

    @XmlAttribute(name = "data")
    private List<T> data;

    [...]
}

I get the following error message at runtime.

Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct     instance of `com.test.myObjInterface` (no Creators, like default construct, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
14:47:41,982 ERROR [stderr] (EJB default - 2)  at [Source: (org.jboss.resteasy.client.jaxrs.internal.ClientResponse$InputStreamWrapper); line: 3, column: 14] (through reference chain: com.test.RestMessageContainer["data"]->java.util.ArrayList[0])

The error is output for the line RestMessageContainer<T> container = response.readEntity(new GenericType<RestMessageContainer<T>>() {});

Is my approach correct at all or how should I solve my problem?

Upvotes: 4

Views: 2589

Answers (2)

Net_Hans
Net_Hans

Reputation: 185

Thanks for your advice, I have several subclasses. There is no information about the type in the JSON strings. The type results from the reqeust address. I couldn't configure Jackson to recognize the subtype. There is no unique field in the JSON strings that I could use as a type. I am not able to change the web service that delivers the JSON strings.


[UPDATE]

I have found a solution. I no longer let the JAX-RS client convert the JSON string. I have the JSON string returned to me as a string and convert it independently using Jackson.

    public <T extends myObjInterface> RestMessageContainer<T> send(String endpointPath, Map<String, String> parameters, Class<T> clazz) {
        [...]
        Response response = webTarget.request(MediaType.APPLICATION_JSON_TYPE).get();

        ObjectMapper mapper = new ObjectMapper();
        mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
        mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

        RestMessageContainer<T> container = mapper.readValue(response.readEntity(String.class), mapper.getTypeFactory().constructParametricType(RestMessageContainer.class, clazz));

        return container;
    }

Upvotes: 1

Piotr Niewinski
Piotr Niewinski

Reputation: 1347

You cannot create an instance of an abstract class. However, you can solve the problem with a simple annotation – @JsonDeserialize on the abstract class:

@JsonDeserialize(as = Cat.class)
abstract class Animal {...}

In your case, the abstract class would be myObjInterface.

Note: If you have more than one subtype of the abstract class, then you should consider including subtype information as shown in this post.

Upvotes: 0

Related Questions