web-dev-qa-db-fra.com

Spring RestTemplate et types génériques Collections ParameterizedTypeReference telles que List <T>

Une classe de contrôleur abstraite requiert une liste d'objets de REST. Lorsque Spring RestTemplate est utilisé, il ne renvoie pas Linked HashMAp à la classe requise.

 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;

}

Si j'utilise,

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

Ça fonctionne bien. Mais ne peut pas mettre dans toutes les sous-classes, aucune autre solution.

20
vels4j

Impossible de trouver une solution de Spring, c'est pourquoi je l'ai fait avec ParameterizedTypeReference dans HashMap comme 

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

et utilisé 

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

J'ai travaillé autour de cela en utilisant la méthode générique suivante:

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

Ensuite, je pourrais appeler:

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

Cela appelait mes appelants à devoir spécifier la ParameterizedTypeReference lors de l'appel, mais signifiait que je n'avais pas à garder un mappage statique des types comme dans la réponse de vels4j

19
Rossiar

Utiliser ParameterizedTypeReference pour un List<Domain>, lorsque Domain est une classe explicite, cela ParameterizedTypeReference fonctionne bien, comme ceci:

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

Toutefois, si une méthode listAll est utilisée dans une version générique, cette liste doit être paramétrée elle-même. Le meilleur moyen que j'ai trouvé pour cela est:

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

La solution la plus simple pour moi est de définir un objet MyOperationResult contenant la liste que vous attendez comme champ et d’utiliser restTemplate.getForObject pour obtenir ce résultat.

0
JRA_TLL