Spring HATEOAS и mockMVC, игнорирует consumes = MediaType.APPLICATION_JSON_UTF8_VALUE

После создания службы с использованием 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, так и application / hal + json, так что документация по крайней мере работает.

Кто-нибудь знает, почему это?


person Wilfred Dittmer    schedule 15.09.2016    source источник


Ответы (1)


Я нашел еще один вопрос о stackoverflow: Spring MVC-контроллер игнорирует свойство consumes

И решение там сработало и для меня. Я добавил @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();
    }
}
person Wilfred Dittmer    schedule 19.09.2016