#spring-boot #jaxb #handler #spring-webflux #spring-reactive
#spring-boot #jaxb #обработчик #spring-webflux #spring-реактивный
Вопрос:
Я пытался реализовать Spring реактивные маршрутизаторы и обработчики вместо контроллеров MVC. Казалось бы, достаточно просто, но мой тест WebTestClient не удался с внутренней ошибкой сервера 500. Короткий код по сравнению с тестом.
@ContextConfiguration(classes = {FooRouter.class, FooServiceConfig.class, FoonHandler.class})
@WebFluxTest
public class FooHandlerTest {
@Test
public void testFooPost() {
webTestClient.post()
.uri("/foot")
.contentType(MediaType.APPLICATION_XML)
.accept(MediaType.APPLICATION_XML)
.body(Mono.just(foo), Foo.class)
.exchange()
.expectStatus().isCreated()
.expectBody(Bar.class)
.isEqualTo(bar);
}
Во время теста маршрутизатор работает нормально и вызывает обработчик. Когда обработчик пытается создать Mono из тела запроса:
Mono<Foo> fooMono = request.bodyToMono(Foo.class);
эта строка завершает модульный тест, и WebTestClient получает код состояния 500. Во время отладки, хотя mime-типом является application / xml и он отображал класс Java, BodyExtractors фильтрует декодеры и сопоставляет класс и тип mime. Для Json он просматривает класс Java и пытается получить от него сопоставление, прежде чем сравнивать тип mime. В глубине отладки происходит сбой, когда он все еще пытается сопоставить класс с object mapper.
В настоящее время я использую Spring Boot версии 2.3.4-RELEASE с Java8. В документации упоминается, что если в вашем пути к классу есть JaxB, то для XML он должен использовать Jaxb2XmlDecoder и Endoder для кодеков по умолчанию. Он также будет использовать Jackson, если он есть в вашем пути к классу. У меня действительно есть оба минус зависимость jackson-dataformat-xml. Я почти уверен, что это либо моя тестовая конфигурация, либо это может быть WebFluxConfigurer, который я попытался установить кодек по умолчанию для jaxb2Decoder и Encoder. Я также попытался добавить зависимость jackson-dataformat-xml, но это тоже не сработало. Это webconfig, который я пытался использовать, но все еще сбой при попытке декодировать mime-типы application / xml с помощью декодера Json. Вот webconfig:
@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {
@Override
public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
configurer.registerDefaults(false);
configurer.defaultCodecs().jaxb2Decoder(new Jaxb2XmlDecoder(MediaType.APPLICATION_XML));
configurer.defaultCodecs().jaxb2Encoder(new Jaxb2XmlEncoder());
}
}
Я отлаживал и распечатывал средства чтения сообщений request objects, а Jaxb2XmlEncoder является одним из кодеков для mime-типа XML. Вот сообщение о печати для декодеров JSON и XML:
Message Reader: org.springframework.http.codec.DecoderHttpMessageReader@5b2cea27
DecoderHttpMessageReader Decoder: org.springframework.http.codec.json.Jackson2JsonDecoder@87b7472
Mime Type: application/json
Mime Type: application/* json
Message Reader: org.springframework.http.codec.DecoderHttpMessageReader@198a86e1
DecoderHttpMessageReader Decoder: org.springframework.http.codec.xml.Jaxb2XmlDecoder@50cb41d0
Mime Type: application/xml
Mime Type: text/xml
Mime Type: application/* xml
Когда в методе readWithMessageReaders в классе BodyExtractors в функции есть фильтр, который выполняет итерацию по считывателям и декодерам сообщений. Когда он попадает в DecoderHttpMessageReader, Jackson2JsonDecoder, он начинает пытаться декодировать запрос. Не уверен, почему, поскольку тип mime в отладчике показывает application / xml.
Есть ли у кого-нибудь предложения по отладке этого фрагмента кода:
Mono<Foo> fooMono = request.bodyToMono(Foo.class);
Именно здесь он умирает во время модульного тестирования с приведенным выше кодом. Я пробовал отладку, но это просто остановит тест, когда я зайду слишком глубоко. Я просто знаю, что он проходит через тип Java, когда пытается сопоставить кодек. Большинство кодеков просто сразу возвращаются, но декодеры Json и XML пытаются получить атрибуты класса Java и задыхаются. Класс является классом JaxB со всеми надлежащими аннотациями. У WebTestClient нет проблем с кодированием класса в XML для теста. Так почему обработчик не может просто преобразовать тело в mono? Из этого оператора кода ничего не выбрасывается.
Ответ №1:
Я знал, что это было что-то в моей настройке, и модульное тестирование не показывало правильную проблему.
Это был мой оператор return, который фактически вызывал ошибку при получении содержимого тела.
Старый оператор возврата:
return created(URI.create(response.getDocument().getPath()))
.bodyValue(Mono.just(response));
Новый оператор возврата:
return created(URI.create(response.getDocument().getPath()))
.body(Mono.just(response), Response.class);
Видите разницу с bodyValue и просто body? Это вызвало невозможность преобразования тела запроса в Mono.