Преобразование JSON сообщения Spring Cloud Stream не работает

Я выполнил свой предыдущий вопрос Сообщение Spring Cloud Stream из / в преобразование JSON конфигурация и настроенный поток, как описано, но я не могу заставить его работать правильно.

Моя установка выглядит следующим образом. У меня есть два приложения A и B. Приложение A использует входной канал one, выходной two. Приложение B использует ввод two. Канал two настроен с типом содержимого application/json.

Приложение A. Свойства.

spring.cloud.stream.bindings.input.destination=one
spring.cloud.stream.bindings.input.group=default

spring.cloud.stream.bindings.output.destination=two
spring.cloud.stream.bindings.output.content-type=application/json

Метод слушателя.

@ServiceActivator(inputChannel = Processor.INPUT, outputChannel = Processor.OUTPUT)
public Dto handle(byte[] payload) throws IOException {
    final Dto dto = new ObjectMapper().readValue(payload, Dto.class);
    logger.info("{}", dto);
    dto.setId(dto.getId() + 1000);
    return dto;
}

Приложение Б. Свойства.

spring.cloud.stream.bindings.input.destination=two
spring.cloud.stream.bindings.input.group=default
spring.cloud.stream.bindings.input.content-type=application/json

Метод слушателя.

@ServiceActivator(inputChannel = Sink.INPUT)
public void handle(Dto dto) throws IOException {
    logger.info("DTO {}", dto);
}

Когда я вручную отправляю сообщение с правильной строкой JSON на канал one, оно обрабатывается правильно и отправляется на канал two как сообщение JSON (заголовки точно такие же, как описано в вышеупомянутом вопросе). После этого приложение B получает его по каналу two, и выдается исключение: Method handle(java.lang.String) cannot be found

Конечно, когда я создаю оба метода, обрабатывая Dto и String в качестве входных данных, он работает, но всегда вызывается метод String, и мне приходится десериализовать полезную нагрузку самостоятельно.

Я где-то ошибаюсь? Как настроить метод с такой подписью: public Dto handle(Dto incoming)?


person wst    schedule 15.03.2016    source источник
comment
Почему вы не использовали StreamListener вместо ServiceActivator для своего приложения Б? Я не уверен на 100%, но думаю, что вашу проблему можно было решить с помощью StreamListener вместо изменения свойства content-type.   -  person Gooseman    schedule 29.01.2017
comment
В то время такой возможности не было. Но да, это хороший совет.   -  person wst    schedule 30.01.2017


Ответы (2)


Вы должны изменить объявление типа содержимого ввода AppB на

application/x-java-object;type=your.package.Dto.

Как указано в вашем вопросе, вы, конечно, принимаете только строки JSON.

person Alexander    schedule 23.03.2016
comment
Мне не нужна сериализация Java. Взгляните на тему - мне нужны сообщения JSON. - person wst; 23.03.2016
comment
Верно, вы оставите объявление типа содержимого вывода AppA для вывода JSON, но AppB следует сообщить через это объявление типа содержимого, что соответствующий MessageConverter должен преобразовать полезную нагрузку в объект Dto. Сообщения на канале будут в формате JSON, как видно во время отладки. - person Alexander; 23.03.2016
comment
Это действительно работает, спасибо. Невероятно неинтуитивно понятный, учитывая, как работают другие компоненты Spring (AMQP или Rest). - person wst; 24.03.2016

если вы используете @StreamListener, вам не нужно использовать способ ответа, но вы должны удалить (ничего не указывайте, иначе это будет строка json):

spring.cloud.stream.bindings.input.content-type=application/json

из свойств AppB

источник (старые документы, но все еще действующие): https://docs.spring.io/spring-cloud-stream/docs/Brooklyn.RELEASE/reference/html/contenttypemanagement.html#__literal_streamlistener_literal_and_message_conversion

person Bashar Ali Labadi    schedule 16.04.2019