web-dev-qa-db-ja.com

Spring RestTemplateおよびList <T>などのジェネリック型ParameterizedTypeReferenceコレクション

抽象コントローラークラスには、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;

}

私が使用する場合、

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

正常に動作します。しかし、すべてのサブクラス、他のソリューションに入れることはできません。

24
vels4j

Springから解決策を見つけることができなかったので、ParameterizedTypeReferenceのようなHashMapでそれをやった

 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>>(){} );
 }

そしてそれを使用しました

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

次の一般的な方法を使用してこれを回避しました。

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

それから私は電話することができます:

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

これは、呼び出し時にParameterizedTypeReferenceを指定しなければならないことで呼び出し側に負担をかけましたが、vels4jの答えのような型の静的マッピングを保持する必要がないことを意味しました

24
Rossiar

List<Domain>ParameterizedTypeReferenceを使用すると、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();
}

ただし、メソッド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();
    }
}
1
Moesio

私にとって最も簡単な解決策は、フィールドとして期待するリストを含むオブジェクトMyOperationResultを定義し、restTemplate.getForObjectを使用してこの結果を取得することです。

1
JRA_TLL