如何在Spring Boot中为Camel配置Jackson ObjectMapper

时间:2015-10-28 17:11:50

标签: spring-boot jackson apache-camel

我正在尝试使用Jackson在Camel路由上与JSON序列化和反序列化POJO。其中一些有Java 8 LocalDate字段,我希望它们被序列化为YYYY-MM-DD字符串,而不是整数数组。

我们只为我们的Spring Boot应用程序使用Java配置,因此没有XML Camel配置。

我已成功创建了一个ObjectMapper,它可以实现我想要的功能,我们系统的其他部分通过将它添加到我们的依赖项中来使用它:

def price(self):
    if self.amazon_url:
        url = self.amazon_url
        source_code = requests.get(url)
        code = html.fromstring(source_code.text)
        prices = code.xpath('//span[@id="priceblock_ourprice"]/text()')
        eur = prices[0].replace("EUR ", "")
        nospace = eur.replace(" ", "")
        nodown = nospace.replace("\n", "")
        end = nodown.replace(",", ".")
        return float(end)
    else:
        return 0

这是我们的应用程序配置:

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

示例传出REST路由:

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

传入消息路由示例:

@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()");
    }
}

但是,默认情况下,Camel会创建自己的ObjectMapper实例,因此不会选择@Component public class MyRouteBuilder extends RouteBuilder { @Autowired private MyBean myBean; @Override public void configure() { from(uri) .unmarshal().json(JsonLibrary.Jackson) .bean(myBean); } } 自动添加的JSR310序列化程序/反序列化程序或禁用的Jackson2ObjectMapperBuilder功能。我已经阅读了Camel JSON文档,但没有说明如何使用Spring配置添加自定义DataFormat,或者如何为所有类型应用全局自定义。

那么我怎样才能告诉Camel使用我的ObjectMapper,只使用Spring Boot Java配置?

10 个答案:

答案 0 :(得分:6)

我已经通过单步执行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而没有unmarshal类型。但是,在默认构造函数中,当没有提供unmarshal类型时使用HashMap.class,所以我使用它。通过一些魔术,这似乎习惯于解组所有POJO类型。如果您还需要其他类的更具体的数据格式,则还需要在其中设置ObjectMapper
  • Camel似乎在bean注册表中搜索一个名为“json-jackson”的bean,因此设置Spring bean使用该名称会欺骗Camel而不是创建一个新的并使用我的。
  • bean范围必须设置为SCOPE_PROTOTYPE,因为REST DSL希望获得DataFormat的新实例。见CAMEL-7880

答案 1 :(得分:3)

在java代码中创建<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center" android:orientation="vertical" > <ImageView android:id="@+id/imageview_fullscreen" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:src="@drawable/ic_launcher" /> </RelativeLayout> 并启用/禁用所需的功能,然后在Camel路由中使用该实例。

JacksonDataFormat

答案 2 :(得分:2)

使用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);
    }
}

答案 3 :(得分:2)

我设法使用org.apache.camel:camel-jackson-starter:2.20.0

非常方便地为Camel配置了ObjectMapper

它通过Spring应用程序属性公开了一些有用的ObjectMapper属性。例如,可以从application.yaml或application.properties文件直接设置WRITE_DATES_AS_TIMESTAMPS。

查找JacksonDataFormatConfiguration类以获取更多详细信息。

我还需要使用一些Mixins,所以我仍然需要配置Camel来使用Spring的ObjectMapper。我最终得到了这个:

配置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的名称

答案 4 :(得分:1)

到目前为止,只有@ 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();
        }
    }
}

答案 5 :(得分:1)

如果有人想知道如何使用版本中的修复程序。 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的名称

答案 6 :(得分:1)

我通过在pom中包含杰克逊依赖项来解决

RealFloat

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

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

答案 7 :(得分:0)

如果Camel在那里给你带来麻烦,我会直接使用bean:

  1. 只需创建一个可以进行编组和解组的小型Json实用程序,并将预配置的ObjectMapper自动装入其中。

  2. 利用Camels很棒的Spring bean集成来调用你的实用程序并转换路由中的Message,例如:

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

答案 8 :(得分:0)

我无法使用任何示例。有点失望的是,阅读变通方法非常复杂。

在我看来,camel应该可以通过使用应用程序附带的相同Jackson bean来轻松使用Spring默认对象映射器。

我放弃使用.json()并将其换成处理器。

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

<强>路线

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

通用处理器注意这是如何自动启动spring引导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()));
    }

}

答案 9 :(得分:0)

大家好消息,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.*下的所有其他属性都将被忽略)