2015-10-28 30 views
7

Sto provando a serializzare e deserializzare POJO da e verso JSON su percorsi Camel usando Jackson. Alcuni di questi hanno campi di LocalDate di Java 8, e voglio che siano serializzati come una stringa YYYY-MM-DD, non come una matrice di interi.Come configurare Jackson ObjectMapper per Camel in Spring Boot

Utilizziamo solo la configurazione Java per la nostra applicazione Spring Boot, quindi nessuna configurazione Camel XML.

ho creato con successo un ObjectMapper che fa quello che voglio, che viene utilizzato da altre parti del nostro sistema aggiungendo questo ai nostri dipendenze:

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

e questo alla nostra configurazione dell'applicazione:

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

Esempio percorso REST in uscita:

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

Exa mple in entrata percorso messaggio:

@Component 
public class MyRouteBuilder extends RouteBuilder { 

    @Autowired 
    private MyBean myBean; 

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

Tuttavia, per impostazione predefinita Camel crea le proprie istanze ObjectMapper quindi non salire su entrambi i JSR310 serializzatori/deserializzatore che Jackson2ObjectMapperBuilder aggiunge automaticamente, o disabili WRITE_DATES_AS_TIMESTAMPS funzione. Ho letto la documentazione Camel JSON, ma non mostra come aggiungere un DataFormat personalizzato utilizzando la configurazione di Spring o come applicare una personalizzazione globale per tutti i tipi.

Quindi, come posso dire a Camel di utilizzare il mio ObjectMapper, usando solo la configurazione Java di Spring Boot?

+0

Vedere le abilitazione/disabilitazione delle funzionalità di jackson: http://camel.apache.org/json.html –

+0

Si prega di condividere il percorso cammello pure. –

+0

@ClausIbsen L'ho letto, ma non mostra come rendere Camel consapevole del DataFormat personalizzato. O come farlo si applica a tutti i POJO piuttosto che a una classe specifica. –

risposta

4

ho trovato una soluzione facendo un passo attraverso il codice Camel. Così mentre fa quello che voglio, potrebbe non funzionare con le versioni future di Camel poiché sembra non documentato e potenzialmente non supportato.

Tutto ciò che faccio è aggiungere il seguente fagioli alla mia Primavera config, in aggiunta ai miei ObjectMapper fagiolo nella domanda:

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

I punti cruciali da notare:

  • Non v'è alcun costruttore per JacksonDataFormat che accetta uno ObjectMapper senza un tipo non razziale.Tuttavia, nel costruttore predefinito viene utilizzato un HashMap.class quando non viene fornito un tipo non razziale, quindi lo uso. Per un po 'di magia, sembra che si abitui a tutti i tipi di POJO. Se sono necessari anche formati di dati più specifici per altre classi, è necessario impostare anche lo ObjectMapper.
  • Camel sembra cercare nel bean bean un bean chiamato "json-jackson", quindi impostare il bean Spring per usare quel nome fa in modo che Camel non ne crei uno nuovo e usi invece il mio.
  • L'ambito del bean deve essere impostato su SCOPE_PROTOTYPE perché il DSL REST prevede di ottenere una nuova istanza di DataFormat. Vedi CAMEL-7880.
+0

Finora questa è stata l'unica cosa che ha funzionato per me. Qualche variazione alla mia soluzione: non c'è bisogno di un objectMapper, ho creato anche un bean con name = "json-jackson" che era un'estensione di JacksonDataFormat. –

+0

Solo l'opzione che ha funzionato anche per me (usando Camel 2.17)! – jfneis

2

Creare il JacksonDataFormat in codice java e abilitare/disabilitare le funzionalità desiderate, quindi utilizzare tale istanza nella rotta Camel.

.unmarshal(myInstanceGoesHere). 
+0

Grazie. Questa è una soluzione parziale; Vedo un certo numero di carenze: 1. Quando si utilizza restConfiguration(), setJsonDataFormat() accetta una stringa, ma non vedo alcun modo per assegnare a JacksonDataFormat un nome.Ogni endpoint di riposo() avrebbe bisogno di un unmarshal() aggiunto? 2. L'aggiunta di un JacksonDataFormat personalizzato per ogni percorso è inefficiente e potrebbe essere dimenticata. Mi piacerebbe configurare a livello globale, una volta. 3. Ho già un ObjectMapper configurato come lo voglio. Sembra inefficiente doverne configurare uno nuovo. Non è solo disabilitando le funzionalità; Devo anche registrare i serializzatori/deserializzatori JSR310. –

+2

Ho registrato un ticket per consentire di configurare un'istanza del programma di analisi dell'oggetto personalizzato da utilizzare per il formato dei dati: https://issues.apache.org/jira/browse/CAMEL-9275 –

+0

Grazie, Claus. A mio avviso, dovrebbe utilizzare automaticamente un bean ObjectMapper esistente se ce n'è uno, e solo creare un nuovo ObjectMapper se non ne esiste uno. –

0

Se Camel ti dà problemi lì, vorrei tornare a utilizzare direttamente i fagioli:

  1. È sufficiente creare un piccolo programma di utilità JSON che può fare di smistamento e unmarshalling e autowire tua ObjectMapper preconfigurato in esso.

  2. cablaggio Cammelli integrazione bean Spring impressionante per chiamare l'utilità e trasformare il messaggio nel percorso, ad es .:

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

Utilizzando primavera e Camel 2.18.1, sono stato in grado di ottenere lo stesso aggiungendo le seguenti dipendenze:

<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> 

e in una classe CamelContextConfiguration, autowiring il JacksonDataFormat al fine di configurare la scoperta di moduli classpath e la configurazione delle opzioni di serializzazione:

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

Finora solo il suggerimento di @ David-Edwards ha lavorato per me. Ho definito un fagiolo formato di dati con l'id: "JSON-jackson"

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

Poi la classe di formato:

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

E la classe 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(); 
     } 
    } 
} 
1

sono riuscito a configurare ObjectMapper per Camel abbastanza comodamente usando org.apache.camel:camel-jackson-starter:2.20.0

Espone un po 'di ha utili proprietà ObjectMapper per la configurazione tramite le proprietà dell'applicazione Spring. Ad esempio, WRITE_DATES_AS_TIMESTAMPS può essere impostato direttamente dal file application.yaml o application.properties.

Cercare la classe JacksonDataFormatConfiguration per ulteriori dettagli.

Avevo anche bisogno di usare alcuni Mixin quindi avevo ancora bisogno di configurare Camel per usare un ObjectMapper di Spring. Ho finito con questo:

fagioli di configurazione:

@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 

Dove jacksonObjectMapper è il nome del chicco ObjectMapper costruito dal Jackson2ObjectMapperBuilder configurato