92

I have a class like that:

public class Wrapper<T> {

 private String message;
 private T data;

 public String getMessage() {
    return message;
 }

 public void setMessage(String message) {
    this.message = message;
 }

 public T getData() {
    return data;
 }

 public void setData(T data) {
    this.data = data;
 }

}

and I use resttemplate as follows:

...
Wrapper<Model> response = restTemplate.getForObject(URL, Wrapper.class, myMap);
Model model = response.getData();
...

However it throws a:

ClassCastException

I read that: Issue when trying to use Jackson in java but didn't help. There are some topics related to my problem etc.: https://jira.springsource.org/browse/SPR-7002 and https://jira.springsource.org/browse/SPR-7023

Any ideas?

PS: My error is that:

java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to a.b.c.d.Model

I think resttemplate can not understand my generic variable and maybe it accepts it as an Object instead of generic T. So it becomes a LinkedHashMap. You can read from it here It says that when explaining from what it marshalls to:

JSON Type | Java Type

object | LinkedHashMap

Community
  • 1
  • 1
kamaci
  • 72,915
  • 69
  • 228
  • 366

3 Answers3

170

ParameterizedTypeReference has been introduced in 3.2 M2 to workaround this issue.

Wrapper<Model> response = restClient.exchange(loginUrl, 
                          HttpMethod.GET, 
                          null, 
                          new ParameterizedTypeReference<Wrapper<Model>>() {}).getBody();

However, the postForObject/getForObject variant was not introduced.

Manimaran Selvan
  • 2,166
  • 1
  • 14
  • 14
  • 1
    I tried another optioned for your guys,@alexanoid . Just first get the response as `String` ,then use Jackson to parse the string to generics object ,see : `String body = restTemplate.exchange(request,String.class).getBody(); ObjectMapper mapper=new ObjectMapper(); DataTablesOutput readValue = mapper.readValue(body, DataTablesOutput.class);` – Alter Hu Dec 19 '16 at 05:29
  • 2
    Why Model cannot here be also generic?, etc. like this: `Model` – zygimantus Jun 13 '17 at 12:40
  • 1
    To complement Alter's answer you can use: `mapper.readValue(body, new TypeReference>(){});` – cs94njw Oct 04 '19 at 08:51
  • 1
    My question also why we can't make Model also generic here ? – u91 Jul 14 '20 at 20:04
12

The only thing I think you could do is creating a new class that extends Wrapper and uses model as a generic.

class WrapperWithModel extends Wrapper<Model>{};

WrapperWithModel response = restTemplate.getForObject(URL, WrapperWithModel.class);

It's not the best solution, but at least you won't have to unmarshall manually the response.

Juan Luis
  • 3,317
  • 4
  • 17
  • 23
2

Do not use generics with RestTemplate. Wrap request and response object with wrapper object that will hide the generics.

Dima
  • 1,774
  • 5
  • 21
  • 31