How to create a Camel route that takes XML and associates some data with JPA annotated POJO?

I am new to Apache Camel and tested us, and here it is ...

I have XML without an XSD schema, which I do not affect. The XML child data element items that I want to bind to my pojo business. This POJO (WeatherCurrent) is already annotated by JPA, and I was thinking of adding JAXB annotation, so the broken XML could be mapped to my POJO.

Since this XML has a root element and I only want its childs (metData), I have a problem how to annotate my POJO, since I cannot use @XmlRootElement.

This is partially described here: http://camel.apache.org/splitter.html when streaming large XML payloads using the chapter of the Tokenizer language. My POJO looks like an xml order element in this example. I need only a few elements from the xml metData element to map to POJO fields.

There is also a Partial marshalling / unmarshalling section at http://camel.apache.org/jaxb.html , but there is no JAVA DSL example (required), as well as how to annotate pojo's work with XML fragments.

So far I have this test code:

import java.io.File; import org.apache.camel.EndpointInject; import org.apache.camel.Exchange; import org.apache.camel.ProducerTemplate; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.component.mock.MockEndpoint; import org.apache.camel.converter.jaxb.JaxbDataFormat; import org.apache.camel.spi.DataFormat; import org.apache.camel.test.junit4.CamelTestSupport; import org.junit.Test; public class WeatherCurrentTest extends CamelTestSupport { @EndpointInject(uri = "file:src/test/resources") private ProducerTemplate inbox; @Override protected RouteBuilder createRouteBuilder() throws Exception { return new RouteBuilder() { @Override public void configure() throws Exception { DataFormat jaxbDataFormat = new JaxbDataFormat("com.mycompany.model.entities.weather");// WARNING two packages for JaxbDataFormat from("file:src/test/resources/?fileName=observation_si_latest.xml&noop=true&idempotent=false") .split() .tokenizeXML("metData") .unmarshal(jaxbDataFormat) .to("mock:meteo"); } }; } @Test public void testMetData() throws Exception { MockEndpoint mock = getMockEndpoint("mock:meteo"); mock.expectedMessageCount(9); File meteo = new File("src/test/resources/observation_si_latest.xml"); String content = context.getTypeConverter().convertTo(String.class, meteo); inbox.sendBodyAndHeader(content, Exchange.FILE_NAME, "src/test/resources/observation_si_latest.xml"); mock.assertIsSatisfied(); } } 

XML (observ_si_latest.xml) is supplied in the form:

 <?xml version="1.0" encoding="UTF-8"?> <data id="MeteoSI_WebMet_observation_xml"> <language>sl</language> <metData> <domain_altitude>55</domain_altitude> <domain_title>NOVA GORICA</domain_title> <domain_shortTitle>BILJE</domain_shortTitle> <tsValid_issued>09.03.2012 15:00 CET</tsValid_issued> <t_degreesC>15</t_degreesC> </metData> <metData> <domain_meteosiId>KREDA-ICA_</domain_meteosiId> 

For brevity, I have left many elements of metData elements. I want to map (among others) domain_title to my JPA-annotated POJO station field, and then save its database, hopefully all in one smart and short Camel route.

POJO (no JAXB annotations yet):

 @Entity @Table(name="weather_current") public class WeatherCurrent implements Serializable { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private int id; private String station; @Temporal( TemporalType.TIMESTAMP) @Column(name="successfully_updated") private Date successfullyUpdated; private short temperature; @Column(name="wind_direction") private String windDirection; } 

I also left many fields and methods.

So, the idea is to map the value of the * domain_title * field to the WeatherCurrent POJO field and do this for each metData element and save the list of WeatherCurrent objects in the database.

Any advice on how to implement this is welcome.

+8
java xml jpa jaxb apache-camel
source share
2 answers

It turns out I had one wrong assumption about the impossibility of using @XmlRootElement. The route and test succeed after I annotated the POJO and added the jaxb.index file next to it. He will make a decision later or tomorrow, while I am on the train.

In a few hours...

JAXB Annotations on POJO (over JPA):

 @Entity @Table(name="weather_current") @XmlRootElement(name = "metData") @XmlAccessorType(XmlAccessType.FIELD) public class WeatherCurrent implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private int id; @XmlElement(name = "nn_shortText") private String conditions; @XmlElement(name = "rh") private short humidity; @XmlElement(name = "msl") private short pressure; @Column(name="pressure_tendency") @XmlElement(name = "pa_shortText") private String pressureTendency; @Temporal( TemporalType.TIMESTAMP) @XmlElement(name = "tsValid_issued") private Date published; @XmlElement(name = "domain_longTitle") private String station; 

allowed me to get a list of WeatherCurrent Exchage objects. Just for the test, I sent each of them to my EchoBean to print one property:

 .unmarshal(jaxbDataFormat).bean(EchoBean.class, "printWeatherStation") 

and EchoBean:

 public class EchoBean { public String printWeatherStation(WeatherCurrent weatherCurrent) { return weatherCurrent.getStation(); } } 

beautifully prints the names of weather stations with a component of the Camel magazine.

The only undocumented thing that bothered me was that I had to put this jaxb.index file in the next WeatherCurrent java source, although it is clear in http://camel.apache.org/jaxb.html it that the jaxb context is initializing through

 DataFormat jaxb = new JaxbDataFormat("com.acme.model"); 
+2
source share

The following dependency is included in the pom.xml folder -

 <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-jaxb</artifactId> <version>2.13.0</version> </dependency> 

Next, comment on the pojo class with @XmlRootElement (name = "employee")

 package com.javainuse.model; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement(name = "employee") @XmlAccessorType(XmlAccessType.FIELD) public class Employee { private String empName; private int empId; public String getEmpName() { return empName; } public void setEmpName(String empName) { this.empName = empName; } public int getEmpId() { return empId; } public void setEmpId(int empId) { this.empId = empId; } } 

Finally, in the RouteBuilder class, define jaxb dataformat and use it in the route.

 // XML Data Format JaxbDataFormat xmlDataFormat = new JaxbDataFormat(); JAXBContext con = JAXBContext.newInstance(Employee.class); xmlDataFormat.setContext(con); from("file:C:/inputFolder").doTry().unmarshal(xmlDataFormat). process(new MyProcessor()).marshal(jsonDataFormat). to("jms:queue:javainuse") 

Source code and more details - Apache Camel - Marshalling / Unmarshalling XML / JSON Data

+2
source share

All Articles