簡體   English   中英

如何在 Spring 引導中為 Camel 配置 Jackson ObjectMapper

[英]How to configure Jackson ObjectMapper for Camel in Spring Boot

我正在嘗試使用 Jackson 在駱駝路線上序列化和反序列化與 JSON 之間的 POJO。 其中一些有 Java 8 LocalDate 字段,我希望它們被序列化為 YYYY-MM-DD 字符串,而不是整數數組。

我們僅將 Java 配置用於我們的 Spring 引導應用程序,因此沒有 XML 駱駝配置。

我已經成功地創建了一個 ObjectMapper 來做我想做的事,通過將它添加到我們的依賴項中,我們系統的其他部分正在使用它:

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
</dependency>

這對我們的應用程序配置:

@Bean
public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
    return builder
            .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
            .build();
}

傳出 REST 路由示例:

@Component
public class MyRouteBuilder extends RouteBuilder {

    @Override
    public void configure() throws Exception {

        restConfiguration().component("servlet").contextPath("/mycontext")
                .port(8080).bindingMode(RestBindingMode.json);

        rest("/myendpoint)
                .get()
                .route()
                .to("bean:myService?method=myMethod()");
    }
}

傳入消息路由示例:

@Component
public class MyRouteBuilder extends RouteBuilder {

    @Autowired
    private MyBean myBean;

    @Override
    public void configure() {
        from(uri)
                .unmarshal().json(JsonLibrary.Jackson)
                .bean(myBean);
    }
}

但是,默認情況下,Camel 創建自己的 ObjectMapper 實例,因此不會使用Jackson2ObjectMapperBuilder自動添加的 JSR310 序列化器/反序列化器或禁用的WRITE_DATES_AS_TIMESTAMPS功能。 我已閱讀Camel JSON文檔,但它沒有顯示如何使用 Spring 配置添加自定義數據格式,或如何為所有類型應用全局自定義。

那么如何告訴 Camel 使用我的 ObjectMapper,僅使用 Spring 引導 Java 配置?

我通過單步執行 Camel 代碼找到了解決方案。 因此,雖然它可以滿足我的要求,但它可能不適用於 Camel 的未來版本,因為它似乎沒有記錄並且可能不受支持。

我所做的就是將以下 bean 添加到我的 Spring 配置中,以及問題中的ObjectMapper bean:

@Bean(name = "json-jackson")
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public JacksonDataFormat jacksonDataFormat(ObjectMapper objectMapper) {
    return new JacksonDataFormat(objectMapper, HashMap.class);
}

需要注意的關鍵點:

  • JacksonDataFormat沒有采用沒有解組類型的ObjectMapper構造函數。 但是,在默認構造函數中,當未提供解組類型時使用HashMap.class ,所以我使用它。 通過某種魔法,這似乎習慣於解組所有 POJO 類型。 如果您還需要其他類的更具體的數據格式,您也需要在其中設置ObjectMapper
  • Camel 似乎會在 bean 注冊表中搜索一個名為“json-jackson”的 bean,因此將 Spring bean 設置為使用該名稱會使 Camel 不創建新的 bean 而是使用我的。
  • bean 范圍必須設置為SCOPE_PROTOTYPE因為 REST DSL 期望獲得DataFormat的新實例。 參見CAMEL-7880

在 Java 代碼中創建JacksonDataFormat並啟用/禁用您想要的功能,然后在 Camel 路由中使用該實例。

 .unmarshal(myInstanceGoesHere).

使用 Spring 和 Camel 2.18.1,我能夠通過添加以下依賴項來實現相同的目標:

<dependency>
    <groupId>com.fasterxml.jackson.module</groupId>
    <artifactId>jackson-module-parameter-names</artifactId>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jdk8</artifactId>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>2.6.1</version>
</dependency>

CamelContextConfiguration類中,自動JacksonDataFormat以配置類路徑模塊的發現和序列化選項的配置:

@Configuration
public class CamelContextConfig implements CamelContextConfiguration {

    @Autowired
    public JacksonDataFormat jacksonDataFormat;

    @Override
    public void beforeApplicationStart(CamelContext camelContext) {
    }

    @Override
    public void afterApplicationStart(CamelContext camelContext) {
        jacksonDataFormat
            .getObjectMapper()
            .findAndRegisterModules()
            .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    }
}

大家好消息,Spring Boot 現在支持對象映射器自動發現! 只需設置此屬性:

camel.dataformat.json-jackson.auto-discover-object-mapper=true

如果設置為 true,那么 Jackson 將在注冊表中查找 objectMapper

文檔: https : //camel.apache.org/components/latest/dataformats/json-jackson-dataformat.html#_spring_boot_auto_configuration

日志:

INFO o.a.c.impl.engine.AbstractCamelContext   : Apache Camel 3.3.0 (CamelContext: camel-1) is starting
INFO o.a.c.c.jackson.JacksonDataFormat        : Found single ObjectMapper in Registry to use: com.fasterxml.jackson.databind.ObjectMapper@20a1b3ae
WARN o.a.c.c.jackson.JacksonDataFormat        : The objectMapper was already found in the registry, no customizations will be applied

(警告只是表示, camel.dataformat.json-jackson.*下的所有其他屬性都被忽略)

到目前為止,只有@david-edwards 的建議對我有用。 我首先定義了一個id為“json-jackson”的數據格式bean

<bean id="json-jackson" class="com.mydomain.JacksonDataFormatExt" />

然后是格式類:

public class JacksonDataFormatExt extends JacksonDataFormat{

    public JacksonDataFormatExt(){
        super();
        setPrettyPrint(true);
        setEnableFeatures(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS.name());
        SimpleModule s = new SimpleModule();
        s.addSerializer(CustomEnum.class, new CustomEnumSerializer());
        addModule(s);
    }
}

和 CustomEnumSerializer 類:

public class CustomEnumSerializer extends JsonSerializer<CustomEnum> {

    @Override
    public void serialize(CustomEnumvalue, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
        String stringValue = value.getNlsText();
        if(stringValue != null && !stringValue.isEmpty() && !stringValue.equals("null")) {
            jgen.writeString(stringValue);
        } else {
            jgen.writeNull();
        }
    }
}

我設法使用org.apache.camel:camel-jackson-starter:2.20.0非常方便地為 Camel 配置了 ObjectMapper

它通過 Spring 應用程序屬性公開了一些有用的 ObjectMapper 屬性以進行配置。 例如,可以直接從 application.yaml 或 application.properties 文件設置 WRITE_DATES_AS_TIMESTAMPS。

查找 JacksonDataFormatConfiguration 類以獲取更多詳細信息。

我還需要使用一些 Mixin,所以我仍然需要配置 Camel 以使用 Spring 的 ObjectMapper。 我結束了這個:

配置豆:

@Bean
public Jackson2ObjectMapperBuilderCustomizer customizer() {
    return new Jackson2ObjectMapperBuilderCustomizer() {
        @Override
        public void customize(Jackson2ObjectMapperBuilder builder) {
            builder.mixIn(Person.class, PersonMixin.class);
        }
    }
}

應用程序.yaml:

camel:
  dataformat:
    json-jackson:
      disable-features: WRITE_DATES_AS_TIMESTAMPS
      object-mapper: jacksonObjectMapper

其中jacksonObjectMapper是配置的 Jackson2ObjectMapperBuilder 構建的 ObjectMapper bean 的名稱

如果其他人想知道如何使用版本中的修復程序。 2.17 .. 我使用這個 xml 配置讓它工作:

 <camel:camelContext id="defaultCamelContext">
       .....
        <camel:dataFormats>
            <camel:json id="json" library="Jackson"  objectMapper="myObjectMapper"/>
        </camel:dataFormats>

 </camel:camelContext>

..其中 myObjectMapper 是 ObjectMapper 類型的 spring bean 的名稱

我通過在 pom 中包含 jackson 依賴來解決

<dependency>
  <groupId>org.apache.camel</groupId>
  <artifactId>camel-jackson-starter</artifactId>
  <version>${camel.version}</version>
</dependency>

現在,只需在路由配置中添加 JacksonDataFormat

public void configure() throws Exception {
    JacksonDataFormat jsonDf = new JacksonDataFormat(Card.class);
    jsonDf.setPrettyPrint(true);

    from("direct:endpoint")
    .marshal(jsonDf)
    .convertBodyTo(String.class)
    .....
}

如果 Camel 在那里給你帶來麻煩,我會恢復直接使用 bean:

  1. 只需創建一個小型 Json 實用程序,它可以進行編組和解組並將預配置的 ObjectMapper 自動裝配到其中。

  2. 利用 Camels 很棒的 Spring bean 集成來調用您的實用程序並轉換路由中的消息,例如:

     from(uri) .unmarshal().json(JsonLibrary.Jackson) .beanRef("jsonUtil", "unmarshal") .bean(myBean);

我無法讓任何示例工作。 有點失望的是,閱讀變通方法非常復雜。

在我看來,camel 應該通過使用應用程序附帶的相同 Jackson bean 來輕松使用 Spring 默認對象映射器。

我放棄使用.json()並將其換成處理器。

如下所示,這里使用了 Spring 提供的 objectMapper。

路線

from(CONSUME_TAG)
 .process("jsonProcessor")
 .to("direct:anotherRoute")
 .end();

通用處理器注意這如何自動裝配 spring boot objectMapper bean。

@Component
public class JsonProcessor implements Processor {

    @Autowired
    ObjectMapper objectMapper;

    @Override
    public void process(Exchange exchange) throws Exception {
        exchange.getOut().setBody(objectMapper.writeValueAsString(exchange.getIn().getBody()));
    }

}

這對我有用(Camel 2.2.0)

    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-jsr310</artifactId>
        <version>2.12.5</version>
    </dependency>

休息配置

            restConfiguration().dataFormatProperty("moduleClassNames", "com.fasterxml.jackson.datatype.jsr310.JavaTimeModule")
                               .dataFormatProperty("disableFeatures", "WRITE_DATES_AS_TIMESTAMPS")

Spring Boot 在啟動期間使用所需jackson-datatype-jsr310模塊配置ObjectMapper ,並將其放入 Spring 上下文。

Camel 的新版本默認不使用ObjectMapper形式 Spring Context 並在沒有jackson-datatype-jsr310的情況下創建自己的ObjectMapper

  1. 對於駱駝的新版本,將此添加到application.yaml中。yaml
camel.dataformat.jackson.auto-discover-object-mapper: true
  1. 用於解組
from("some").unmarshal().json(SomeClass.class)

並且不要使用

from("some").unmarshal(new JacksonDataFormat(SomeClass.class))

它不會從 Spring 上下文中獲取ObjectMapper

要檢查會發生什么調試AbstractJacksonDataFormat.doStart()方法。 它在 Camel 啟動期間被調用並從 Spring 上下文中獲取ObjectMapper或創建一個新的。 創建新的ObjectMapper時,它不需要 Jackson jackson-datatype-jsr310模塊並發生錯誤。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM