【问题标题】:Spring MVC Test with RestTemplate: Generic collection fails (even with ParameterizedTypeReference)使用 RestTemplate 进行 Spring MVC 测试:通用集合失败(即使使用 ParameterizedTypeReference)
【发布时间】:2016-09-07 17:17:28
【问题描述】:

我正在使用 Spring Framework 4.3.1

我有以下域类

@XmlRootElement(name="persona")
@XmlType(propOrder = {"id","nombre","apellido","fecha"})
public class Persona implements Serializable {

    @XmlElement(name="id")
    @JsonProperty("id")
    public String getId() {
        return id;
    }

    ....

每个 getter 都有 @XmlElement@JsonProperty 注释。 我正在使用 JAXB2Jackson2

我也有以下:

@XmlRootElement(name="collection")
public class GenericCollection<T> {

    private Collection<T> collection;

    public GenericCollection(){

    }

    public GenericCollection(Collection<T> collection){
        this.collection = collection;
    }

    @XmlElement(name="item")
    @JsonProperty("collection")
    public Collection<T> getCollection() {
        return collection;
    }

    public void setCollection(Collection<T> collection) {
        this.collection = collection;
    }

    @Override
    public String toString() {
      StringBuilder builder = new StringBuilder();
      for(Object object : collection){
        builder.append("[");
        builder.append(object.toString());
        builder.append("]");
      }
      return builder.toString();
    }

}

关于测试,许多@Tests 方法通过Spring MVC Test 工作正常。 @Controller@RestController 按预期工作。

注意:我可以测试 CRUD 场景,它与 HTTP methods 有关,例如 POSTPUTGETDELETE。因此,我能够获得一个实体和一组实体。

注意:从之前的说明来看,所有工作都围绕XMLJSON 格式工作。

现在尝试通过RestTemplate 测试一种程序化客户端,它 失败 用于集合。带有以下内容:

@Before
public void setUp(){
    mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
    restTemplate = new RestTemplate(new MockMvcClientHttpRequestFactory(mockMvc));

    List<HttpMessageConverter<?>> converters = new ArrayList<>();
    converters.add(httpMessageConverterConfig.marshallingMessageConverter());
    converters.add(httpMessageConverterConfig.mappingJackson2HttpMessageConverter());

    restTemplate.setMessageConverters(converters);
    System.out.println("converters.size():" + converters.size());
}

我可以确认converters.size() 总是打印2

以下是针对 XML 和 JSON 的

@Test
public void findAllXmlTest(){

    RequestEntity<Void> requestEntity = RestControllerSupport_.createRequestEntityForGet(uri, retrieveURI);

    ParameterizedTypeReference<GenericCollection<Persona>> parameterizedTypeReference = new ParameterizedTypeReference<GenericCollection<Persona>>(){};
    ResponseEntity<GenericCollection<Persona>> responseEntity = restTemplate.exchange(requestEntity, parameterizedTypeReference);

    assertThat(responseEntity, notNullValue());

    assertThat(responseEntity.getStatusCode(), is(HttpStatus.OK));
    assertThat(responseEntity.getHeaders().getContentType(), is(MediaType.APPLICATION_XML) );

    assertThat(responseEntity.getBody(), notNullValue());
    assertThat(responseEntity.getBody().getClass(), is(GenericCollection.class));
    assertThat(responseEntity.getBody().getCollection(), is(personas));

}

@Test
public void findAllJsonTest(){

    RequestEntity<Void> requestEntity = RestControllerSupport_.createRequestEntityForGet(uri, retrieveURI);

    ParameterizedTypeReference<GenericCollection<Persona>> parameterizedTypeReference = new ParameterizedTypeReference<GenericCollection<Persona>>(){};
    ResponseEntity<GenericCollection<Persona>> responseEntity = restTemplate.exchange(requestEntity, parameterizedTypeReference);

    assertThat(responseEntity, notNullValue());

    assertThat(responseEntity.getStatusCode(), is(HttpStatus.OK));
    assertThat(responseEntity.getHeaders().getContentType(), is(MediaType.APPLICATION_JSON_UTF8) );

    assertThat(responseEntity.getBody(), notNullValue());
    assertThat(responseEntity.getBody().getClass(), is(GenericCollection.class));
    assertThat(responseEntity.getBody().getCollection(), is(personas));

}

注意:注意我在这两种情况下都使用ParameterizedTypeReference

对于 JSON,它可以工作。

但对于 XML,我得到:

org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [com.manuel.jordan.controller.support.GenericCollection<com.manuel.jordan.domain.Persona>] and content type [application/xml]
    at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:109)

出了什么问题或遗漏了什么?

【问题讨论】:

  • Manuel 你能分享你的 pom 吗?和配置
  • 我正在使用Gradle,刚刚分享了关于依赖项的Spring Framework 配置。让我知道您想查看哪个特定部分。

标签: spring spring-mvc spring-test-mvc


【解决方案1】:

您使用MarshallingHttpMessageConverter 而不是GenericHttpMessageConverter 的问题,就像HttpMessageConverterExtractor 中的ParameterizedTypeReference 所预期的那样:

if (messageConverter instanceof GenericHttpMessageConverter) {
                GenericHttpMessageConverter<?> genericMessageConverter =
                        (GenericHttpMessageConverter<?>) messageConverter;
                if (genericMessageConverter.canRead(this.responseType, null, contentType)) {

MappingJackson2HttpMessageConverter 就是那个。

所以,我建议你试试Jaxb2CollectionHttpMessageConverter

【讨论】:

  • 有意思,我会研究一下Jaxb2CollectionHttpMessageConverter。挺有趣的。我使用Spock Framework 并使用此行responseEntity = restTemplate.exchange(requestEntity, GenericCollection.class) 和工作几乎相同的代码(其他项目的先前版本)。遗憾的是,该行无法在 Java 中编译
猜你喜欢
  • 1970-01-01
  • 2016-04-01
  • 2017-06-23
  • 2020-11-12
  • 2013-07-06
  • 2022-11-24
  • 1970-01-01
  • 2022-01-05
  • 1970-01-01
相关资源
最近更新 更多