Java Spring RestTemplate 和泛型类型 ParameterizedTypeReference 集合,如 List<T>

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/36915823/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 18:49:07  来源:igfitidea点击:

Spring RestTemplate and generic types ParameterizedTypeReference collections like List<T>

javaresttemplatespring-restspring-web

提问by vels4j

An Abstract controller class requires List of objects from REST. While using Spring RestTemplate its not mapping it to required class instead it returns Linked HashMAp

抽象控制器类需要来自 REST 的对象列表。使用 Spring RestTemplate 时,它​​没有将其映射到所需的类,而是返回 Linked HashMAp

 public List<T> restFindAll() {

    RestTemplate restTemplate = RestClient.build().restTemplate();
    ParameterizedTypeReference<List<T>>  parameterizedTypeReference = new ParameterizedTypeReference<List<T>>(){};
    String uri= BASE_URI +"/"+ getPath();

    ResponseEntity<List<T>> exchange = restTemplate.exchange(uri, HttpMethod.GET, null,parameterizedTypeReference);
    List<T> entities = exchange.getBody();
    // here entities are List<LinkedHashMap>
    return entities;

}

If I use,

如果我使用,

ParameterizedTypeReference<List<AttributeInfo>>  parameterizedTypeReference = 
    new ParameterizedTypeReference<List<AttributeInfo>>(){};
    ResponseEntity<List<AttributeInfo>> exchange =
  restTemplate.exchange(uri, HttpMethod.GET, null,parameterizedTypeReference);

It works fine. But can not put in all subclasses, any other solution.

它工作正常。但不能放入所有子类,任何其他解决方案。

采纳答案by Rossiar

I worked around this using the following generic method:

我使用以下通用方法解决了这个问题:

public <T> List<T> exchangeAsList(String uri, ParameterizedTypeReference<List<T>> responseType) {
    return restTemplate.exchange(uri, HttpMethod.GET, null, responseType).getBody();
}

Then I could call:

然后我可以打电话:

List<MyDto> dtoList = this.exchangeAsList("http://my/url", new ParameterizedTypeReference<List<MyDto>>() {});

This did burden my callers with having to specify the ParameterizedTypeReferencewhen calling, but meant that I did not have to keep a static mapping of types like in vels4j's answer 

这确实给我的调用者带来了必须指定ParameterizedTypeReference调用时间的负担,但这意味着我不必像 vels4j 的回答那样保留类型的静态映射 

回答by vels4j

Couldnt find a solution from Spring, hence I have done it with ParameterizedTypeReferencein HashMaplike

不可能找到春天的解决方案,因此我与它做ParameterizedTypeReferenceHashMap

 public final static HashMap<Class,ParameterizedTypeReference> paramTypeRefMap = new HashMap() ;
 static {
    paramTypeRefMap.put(AttributeDefinition.class, new ParameterizedTypeReference<List<AttributeDefinition>>(){} );
    paramTypeRefMap.put(AttributeInfo.class, new ParameterizedTypeReference<List<AttributeInfo>>(){} );
 }

and used it

并使用它

ParameterizedTypeReference parameterizedTypeReference = paramTypeRefMap.get(requiredClass);
ResponseEntity<List> exchange = restTemplate.exchange(uri, HttpMethod.POST, entity, parameterizedTypeReference);

回答by Moesio

Using ParameterizedTypeReferencefor a List<Domain>, when Domain is an explicit class, that ParameterizedTypeReferenceworks well, like this:

使用ParameterizedTypeReferencefor a List<Domain>,当 Domain 是一个显式类时,ParameterizedTypeReference效果很好,如下所示:

@Override
public List<Person> listAll() throws Exception {
    ResponseEntity<List<E>> response = restTemplate.exchange("http://example.com/person/", HttpMethod.GET, null,
            new ParameterizedTypeReference<List<Person>>() {});
    return response.getBody();
}

However, if a method listAllis used in generic flavor, that list should be parameterized itself. The best way I found for this is:

但是,如果listAll在通用风格中使用了一个方法,则该列表本身应该被参数化。我为此找到的最好方法是:

public abstract class WebServiceImpl<E> implements BaseService<E> {

    private Class<E> entityClass;

    @SuppressWarnings("unchecked")
    public WebServiceImpl() {
        this.entityClass = (Class<E>) ((ParameterizedType) getClass().getGenericSuperclass())
            .getActualTypeArguments()[0];
    }


    @Override
    public List<E> listAll() throws Exception {
        ResponseEntity<List<E>> response =  restTemplate.exchange("http://example.com/person/", HttpMethod.GET, null,
                new ParameterizedTypeReference<List<E>>() {
                    @Override
                    public Type getType() {
                        Type type = super.getType();
                        if (type instanceof ParameterizedType) {
                            Type[] responseWrapperActualTypes = { entityClass };
                            ParameterizedType responseWrapperType = new ParameterizedTypeImpl(List.class,
                                    responseWrapperActualTypes, null);
                            return responseWrapperType;
                        }
                        return type;
                    }
                });
        return response.getBody();
    }
}

回答by JRA_TLL

The easiest solution for me is to define an object MyOperationResult containing the list you expect as field and use restTemplate.getForObject to get this result.

对我来说,最简单的解决方案是定义一个对象 MyOperationResult ,其中包含您期望作为字段的列表,并使用 restTemplate.getForObject 来获取此结果。

回答by Ken Joyner

I did this a bit different. In my situation, I had a base class where I was implementing a set of CRUD operations and then using derived classes to implement specific resource types.

我这样做有点不同。在我的情况下,我有一个基类,我在其中实现了一组 CRUD 操作,然后使用派生类来实现特定的资源类型。

In the base class, I was trying to define a ParameterizedTypeReference as follows:

在基类中,我试图定义一个 ParameterizedTypeReference 如下:

ParameterizedTypeReference<ServicePagedResult<R>> typeRef = 
  new ParameterizedTypeReference<ServicePagedResult<R>>() {};

This didn't work so I ended up creating an abstract method in the base class:

这不起作用,所以我最终在基类中创建了一个抽象方法:

protected abstract ParameterizedTypeReference<ServicePagedResult<R>> 
getServicePagedResultTypeRef();

and then in the derived classes:

然后在派生类中:

@Override
protected ParameterizedTypeReference<ServicePagedResult<AccountResource>>
getServicePagedResultTypeRef() {
  return new ParameterizedTypeReference<ServicePagedResult<AccountResource>>() {};
}

I could then use that in the base class like:

然后我可以在基类中使用它,例如:

ResponseEntity<ServicePagedResult<R>> response = lbRestTemplate.exchange(
  uri, HttpMethod.GET, null, getServicePagedResultTypeRef(), uriVariables);

回答by ELavicount

In case someone need a Kotlin solution, you can do:

如果有人需要 Kotlin 解决方案,您可以执行以下操作:

val responseType = object : ParameterizedTypeReference<Map<String, Any?>>() {}         
val request = HttpEntity<Any?>(data)
val response = restTemplate.exchange(url, HttpMethod.POST, request, responseType)
val responseMap = response?.body as Map<String, Any>