3
\$\begingroup\$

I have written some code using RESTEasy to handle RESTful service calls and parse the response XML into relevant JAXB annotated classes. At the moment I have seperate methods for each return type:

public class RestBase {
    protected final RestClient restClient;

    public RestBase() {
        restClient = RestManager.getClient();
    }

    protected List<GridNodeDTO> getGridNodes(String path, List<String[]> params){
        Response entity = getEntity(path, params);
        return entity.readEntity(new GenericType<List<GridNodeDTO>>() {});
    }

    protected UnauthorizedAgentDTO getAgent(String path, List<String[]> params){
        Response entity = getEntity(path, params);
        return entity.readEntity(new GenericType<UnauthorizedAgentDTO>() {});
    }

    // other types skipped ...

    protected Response getEntity(String path, List<String[]> params) {
        ResteasyWebTarget target = getTarget();
        target = target.path(path);
        if (params != null) {
            for (String[] s : params) {
                target = target.queryParam(s[0], s[1]);
            }
        }

        Response response = target.request(MediaType.APPLICATION_XML).get();
        if (response.getStatus() != Response.Status.OK.getStatusCode()) {
            throw new RuntimeException(String.format("Invalid response status: %d\n%s", response.getStatus(), response));
        }
        return response;
    }

    private ResteasyWebTarget getTarget() {
        ResteasyClient client = new ResteasyClientBuilder().build();
        ResteasyWebTarget target = client.target(UriBuilder.fromUri(PropertiesHandler.getPropertyByKey("restUrl")).build());
        client.register(new AddAuthHeadersRequestFilter(restClient.getUser(), restClient.getPass()));
        return target;
    }

Could I reduce the amount of code by using generics? I have had some luck with using:

@SuppressWarnings("unchecked")
protected <T> T getRestResponse(String path, List<String[]> params, final Class<T> type) {
    // skipped ... getResponse()
    return (T)response.readEntity(new GenericType(type) {});
}

But this does not work with lists, because it seems, that the program knows nothing of generic type of list at runtime. And it seems that the compiler also kind of knows it (type erasure). What ways there are to optimize my routines?

\$\endgroup\$
6
\$\begingroup\$

I managed to get RESTEasy to work with generics (both lists and single objects) and parse the response to JAXB annotated classes by using the following code that uses reflection:

<T> List<T> getList(String path, List<String[]> params, final Class<T> clazz) {
    GenericType<List<T>> type = getListType(clazz);
    Response entity = getEntity(path, params);
    return entity.readEntity(type);
}

<T> T getObject(String path, List<String[]> params, final Class<T> type) {
    Response entity = getEntity(path, params);
    return (T)entity.readEntity(new GenericType(type) {});
}

private <T> GenericType<List<T>> getListType(final Class<T> clazz) {
    ParameterizedType genericType = new ParameterizedType() {
        public Type[] getActualTypeArguments() {
            return new Type[]{clazz};
        }

        public Type getRawType() {
            return List.class;
        }

        public Type getOwnerType() {
            return List.class;
        }
    };
    return new GenericType<List<T>>(genericType) { };
}
| improve this answer | |
\$\endgroup\$
4
\$\begingroup\$

You mean something like this?

protected <T> List<T> getRestResponseList(String path, List<String[]> params, final Class<T> type) {
    // skipped ... getResponse()
    return (List<T>) response.readEntity(new GenericType<List<T>>() {});
}

UPDATE (addressing comment) I didn't know GenericType before and only skimmed the documentation (if it is J2EE's GenericType).

What you want seems to be impossible, because you need a recursive GenericType and it seems to be shallow. List also wouldn't do because List can not be instantiated.

Maybe new GenericType<List<T>>(new ArrayList<T>().class) could work as a parameter, but I doubt it - I can't see how <T> would be resolved and you don't gain much from it.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Yes, something like this, but I want to specify what T is in calling method. So that it would be List<MyType> not interface java.util.List. \$\endgroup\$ – Erki M. Aug 22 '14 at 11:06
  • 1
    \$\begingroup\$ In what way does my code not provide that? \$\endgroup\$ – Arne Aug 22 '14 at 11:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.