web-dev-qa-db-ja.com

Spring Bootでキャメル用にJackson ObjectMapperを構成する方法

ジャクソンを使用してラクダのルートでJSONとの間でPOJOをシリアル化および逆シリアル化しようとしています。これらの一部にはJava 8 LocalDateフィールドがあり、整数の配列としてではなく、YYYY-MM-DD文字列としてシリアル化する必要があります。

Spring BootアプリケーションではJava構成のみを使用するため、XML Camel構成は使用しません。

これを依存関係に追加することで、システムの他の部分で使用されている、私が望むことを実行する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 route:

@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構成を使用してカスタムDataFormatを追加する方法や、すべてのタイプにグローバルカスタマイズを適用する方法は示されていません。

では、Spring Boot Java configurationのみを使用して、ObjectMapperを使用するようにCamelに指示するにはどうすればよいですか?

16
David Edwards

ラクダのコードをステップスルーして解決策を見つけました。したがって、私が望んでいることは行いますが、ドキュメント化されておらず、サポートされていない可能性があるため、将来のバージョンのCamelでは動作しない可能性があります。

私がしているのは、質問のObjectMapper Beanに加えて、Spring構成に次の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は「json-jackson」と呼ばれるBeanをBeanレジストリーで検索しているように見えるため、Spring Beanにその名前を使用するように設定すると、Camelは新しい名前を作成せず、代わりにmineを使用します。
  • REST DSLはDataFormatの新しいインスタンスを取得することを期待しているため、BeanのスコープをSCOPE_PROTOTYPEに設定する必要があります。詳細は CAMEL-788 を参照してください) =。
7
David Edwards

JavaコードでJacksonDataFormatを作成し、必要な機能を有効/無効にして、キャメルルートでそのインスタンスを使用します。

 .unmarshal(myInstanceGoesHere).
3
Claus Ibsen

ObjectMapper for Camelをorg.Apache.camel:camel-jackson-starter:2.20.0

これは、Springアプリケーションのプロパティを介した構成に役立つObjectMapperプロパティの一部を公開します。たとえば、WRITE_DATES_AS_TIMESTAMPSは、application.yamlまたはapplication.propertiesファイルから直接設定できます。

詳細については、JacksonDataFormatConfigurationクラスを探してください。

また、いくつかのMixinを使用する必要があったため、SpringのObjectMapperを使用するようにCamelを構成する必要がありました。私はこれで終わりました:

構成Bean:

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

application.yaml:

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

ここで、jacksonObjectMapperは、構成されたJackson2ObjectMapperBuilderによって構築されたObjectMapper Beanの名前です。

2
mtiitson

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);
    }
}
2

これまでのところ、@ david-edwardsの提案のみが機能しました。最初に、「json-jackson」というIDのデータ形式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();
        }
    }
}
2

他の誰かが修正を使用する方法を疑問に思っている場合は、ver。 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の名前です。

1
Jacek Obarymski

どの例も機能しませんでした。これが回避策を読むことからかなり複雑であることに少しがっかりした。

私の意見では、キャメルはアプリケーションに付属しているものと同じジャクソンBeanを使用して、Springのデフォルトのオブジェクトマッパーを簡単に使用できるようにする必要があります。

私は.json()の使用を忘れて、プロセッサと交換しました。

次のように、これはSpringが提供するobjectMapperを使用しました。

ルート

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

Generic ProcessorこのAutowireがどのように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()));
    }

}
0
Robbo_UK

Camelで問題が発生した場合は、直接Beanを使用するように戻します。

  1. マーシャリングとアンマーシャリングを実行し、事前構成されたObjectMapperを自動配線できる小さなJsonユーティリティを作成するだけです。

  2. ハーネスキャメルは、ユーティリティを呼び出してルート内のメッセージを変換するための素晴らしいSpring Bean統合です。例:

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

ジャクソン依存関係をpomに含めることで解決しました

<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)
    .....
}
0
Prateek Mehta