Spring Integration Java DSL - Как настроить преобразователь JSON для получения глобальных настроек загрузки Spring?

Я использую поток интеграции для вызова веб-службы RESTful следующим образом:

@Bean
IntegrationFlow flow() throws Exception {
    return IntegrationFlows.from("inputChannel")
            .handle(Http.outboundGateway("http://provider1.com/...")
                    .httpMethod(HttpMethod.GET)
                    .expectedResponseType(ItemDTO[].class))
            .get();
}

Фактически, приведенный выше код работает отлично. Как я понимаю из документации, исходящий HTTP-шлюз Spring интеграции использует экземпляр RestTemplate для преобразования тела ответа Http в массив ItemDTOs.

Давайте теперь рассмотрим следующий код:

@Bean
IntegrationFlow flow() throws Exception {
    return IntegrationFlows.from("inputChannel")
            .handle(Http.outboundGateway("http://provider2.com/...")
                    .httpMethod(HttpMethod.GET)
                    .expectedResponseType(String.class))
            .<String,String>transform(m -> sirenToHal(m))
            .transform(Transformers.fromJson(ItemDTO[].class))
            .get();
}

В этом случае тело ответа Http преобразуется в строку, которая передается преобразователю (например, в моем реальном проекте я использую JOLT для преобразования документа сирены в представление ресурсов HAL - JSON). Затем я создаю экземпляр преобразователя для обработки сопоставления JSON с объектами Java. Удивительно, но приведенный выше код не работает (например, в моем проекте трансформатор выдает UnrecognizedPropertyException).

Причина сбоя, по-видимому, в том, что преобразователь объектов, используемый преобразователем, не настроен таким же образом, как RestTemplate. Интересно, почему преобразователь не использует тот же ObjectMapper, что и экземпляр RestTemplate, или, по крайней мере, почему они не используют ту же конфигурацию (т.е. глобальную конфигурацию загрузки Spring). В любом случае, можно ли настроить ObjectMapper для использования преобразователем?

Обновлять

Я узнал, как настроить отображение объектов трансформера.

Сначала мы создаем и настраиваем экземпляр ObjectMapper Джексона следующим образом:

ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// + any other additional configuration setting

Затем мы создаем экземпляр трансформатора следующим образом (заменяя соответствующую строку в приведенном выше коде):

.transform(Transformers.fromJson(ItemDTO[].class, new Jackson2JsonObjectMapper(mapper)))

Я все еще думаю, что ObjectMapper, используемый трансформатором, должен принимать глобальную конфигурацию загрузки Spring.


person user3329862    schedule 20.04.2016    source источник


Ответы (1)


Это интересный момент, но поскольку вы не вводите RestTemple в Http.outboundGateway(), и даже MappingJackson2HttpMessageConverter, я вижу разницу только между ObjectToJsonTransformer и MappingJackson2HttpMessageConverter, эта Spring Integration использует только new ObjectMapper(), когда Spring Web делает это в своем коде:

public MappingJackson2HttpMessageConverter() {
    this(Jackson2ObjectMapperBuilder.json().build());
}

Даже если Spring Boot автоматически настроит ObjectMapper bean-компонент, я не вижу никаких ссылок на все эти функции в этом жестком коде.

Итак, подтвердите, что Jackson2ObjectMapperBuilder.json().build() работает и для вас, и не стесняйтесь поднимать заявку на JIRA для гармонизации инфраструктуры Spring Integration ObjectMapper со Spring Web.

ОБНОВЛЕНИЕ

OK. Кажется, я нашел разницу. И я был прав - Jackson2ObjectMapperBuilder:

// Any change to this method should be also applied to spring-jms and spring-messaging
// MappingJackson2MessageConverter default constructors
private void customizeDefaultFeatures(ObjectMapper objectMapper) {
    if (!this.features.containsKey(MapperFeature.DEFAULT_VIEW_INCLUSION)) {
        configureFeature(objectMapper, MapperFeature.DEFAULT_VIEW_INCLUSION, false);
    }
    if (!this.features.containsKey(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)) {
        configureFeature(objectMapper, DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }
}

Итак, мы должны применить эти параметры и к Spring Integration. См. Также MappingJackson2MessageConverter.

JIRA по этому вопросу: https://jira.spring.io/browse/INT-4001

person Artem Bilan    schedule 20.04.2016
comment
Еще раз большое спасибо за помощь Артему. У меня есть еще один вопрос, тесно связанный с моим примером: можно ли настроить преобразователь JSON для обработки коллекций? В моем примере кода я могу использовать ParameterizedTypeReference с компонентом исходящего шлюза, но то же самое нельзя использовать с преобразователем JSON. Можете ли вы добавить это в качестве улучшения для будущих выпусков? Дайте мне знать, если вы предпочитаете, чтобы я написал новый пост по этому вопросу. - person user3329862; 21.04.2016
comment
Что ж, ParameterizedTypeReference является частью Spring Web API и вообще не имеет отношения к Джексону. У нас есть крючки в JsonToObjectTransformer к возможным трюкам Джексона с типами по JsonHeaders. См. Раздел JSON Transformers в docs.spring.io / Spring-integration / reference / html /. Для типа коллекции вы должны использовать заголовки JsonHeaders.TYPE_ID и JsonHeaders.CONTENT_TYPE_ID в запросе Message. Но с другой стороны вместо коллекции можно указать тип массива, например. type="com.my.proj.tPerson[]". - person Artem Bilan; 21.04.2016
comment
А как насчет TypeReference Джексона? Я имею в виду, было бы здорово, если бы у нас было что-то вроде: Transformers.fromJson(new TypeReference<List<ItemDTO>() {}). Я думаю, что это упростило бы, например, агрегирование групп сообщений, как в моем примере здесь. - person user3329862; 21.04.2016
comment
Да, я понимаю вашу точку зрения. Но преобразователи Spring Integration свободны от целевой реализации движка JSON. Мы используем нашу собственную JsonObjectMapper абстракцию. Как я уже сказал: не стесняйтесь создавать JIRA, и мы подумаем, что делать с ParameterizedTypeReference. Когда он появится в ядре SI, мы можем добавить такой трюк в фабрику DSL Transformers.fromJson(). - person Artem Bilan; 21.04.2016