Spring HATEOAS和mockMVC,忽略consumemes = MediaType.APPLICATION_JSON_UTF8_VALUE

时间:2016-09-15 12:58:39

标签: json spring hateoas mockmvc hal

使用Spring HATEOAS创建服务并使用mockmvc测试它(也使用Spring restdocs生成文档)后,我们发现了以下内容。

我们的RestController看起来像:

@RestController
@RequestMapping("/v1/my")
@ExposesResourceFor(My.class)
@EnableHypermediaSupport(type = EnableHypermediaSupport.HypermediaType.HAL)
public class MyController {

   @Autowired
   private MyRepository myRepository;

   @Autowired
   private MyResourceAssembler myResourceAssembler;

   @RequestMapping(path = "", method = POST, consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
   public HttpEntity<Resource<MyResource>> addMy(
        @RequestBody MyResource newMyResource) {

    if (myRepository.existsByMyId(newMyResource.getMyId())) {
        return new ResponseEntity<>(HttpStatus.CONFLICT);
    }

    val newMy = new My(
            null, // generates id
            newMy.getMyId()
    );

    val myResource = myResourceAssembler.toResource(myRepository.save(newMy));
    val resource = new Resource<>(myResource);

    return new ResponseEntity<>(resource, HttpStatus.CREATED);
   }
}

为了测试这个,我们创建了以下测试:

@Test
public void addMy() throws Exception {
    this.mockMvc.perform(post("/v1/my")
            .content("{ \"myId\": 9911 }")
            .contentType(MediaType.APPLICATION_JSON_UTF8)
            .accept(MediaTypes.HAL_JSON))
            .andExpect(status().isCreated())
            .andExpect(MockMvcResultMatchers.jsonPath("$.myId").value(9911))   
            .andDo(this.document.document(selfLinkSnippet, responseFieldsSnippet));
}

我们得到的单元测试结果是:

java.lang.AssertionError: Status 
Expected :201
Actual   :415

状态代码415是不支持的媒体类型。

如果我们修改单元测试说:

.contentType(MediaTypes.HAL_JSON)

单元测试返回成功。这很奇怪,因为我们指示只使用application / json。 现在的问题是生成的文档错误地指出POST请求应该使用Content-type application / hal + json:

curl 'http://my-service/v1/my' -i -X POST -H 'Content-Type: application/hal+json' -H 'Accept: application/hal+json' -d '{ "myId": 9911 }'

如果你尝试这样做,你将得到另一个415。 如果我们将Content-Type:更改为application / json,那么它确实有效。

如果我们告诉方法同时使用HAL + JSON和JSON:

@RequestMapping(path = "", method = POST, consumes = { MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_UTF8_VALUE})

然后在设置contentType(MediaTypes.HAL_JSON)时单元测试成功,但在设置了contentType(MediaType.APPLICATION_JSON_UTF8)时失败。

但是,现在服务都接受application / json AND application / hal + json,这样文档至少可以正常工作。

有谁知道这是为什么?

1 个答案:

答案 0 :(得分:0)

我发现了另一个stackoverflow问题:Spring MVC controller ignores "consumes" property

那里的解决方案也适用于我。我将@EnableWebMvc添加到测试配置类。

@EnableWebMvc
@Configuration
@Import({CommonTestConfiguration.class})
@EnableHypermediaSupport(type = EnableHypermediaSupport.HypermediaType.HAL)
public class MyControllerTestConfiguration {

    @Bean
    public MyRepository myRepository() {

        return new InMemoryMyRepository();
    }

    @Bean
    public MyController myController() {
        return new MyController();
    }

    @Bean
    public MyResourceAssembler myResourceAssembler() {
        return new myResourceAssembler();
    }
}