Spring RestTemplate and generic types ParameterizedTypeReference collections like List

前端 未结 6 660
一生所求
一生所求 2020-12-05 09:44

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

相关标签:
6条回答
  • 2020-12-05 10:13

    Using ParameterizedTypeReference for a List<Domain>, when Domain is an explicit class, that ParameterizedTypeReference works well, like this:

    @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 listAll is used in generic flavor, that list should be parameterized itself. The best way I found for this is:

    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();
        }
    }
    
    0 讨论(0)
  • 2020-12-05 10:23

    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.

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

    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);
    
    0 讨论(0)
  • 2020-12-05 10:25

    Couldnt find a solution from Spring, hence I have done it with ParameterizedTypeReference in HashMap like

     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);
    
    0 讨论(0)
  • 2020-12-05 10:26

    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.

    0 讨论(0)
  • 2020-12-05 10:30

    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 ParameterizedTypeReference when calling, but meant that I did not have to keep a static mapping of types like in vels4j's answer 

    0 讨论(0)
  • 2020-12-05 10:33

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

    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>
    
    0 讨论(0)
提交回复
热议问题