I am new to Apache Camel and mock testing so here it goes...
I have an XML with no XSD schema which I have no influence on. Child elements of this XML hold data which I want to bind to my business pojo. This POJO (WeatherCurrent) is already JPA annotated and I was thinking of adding JAXB annotation so the splitted XML could be mapped to my POJO.
As this XML has a root element and I only want its childs (metData) I have a problem how to annotate my POJO as I can not use @XmlRootElement.
This is partialy described here: http://camel.apache.org/splitter.html at Streaming big XML payloads using Tokenizer language chapter. My POJO is like order xml element in that example. I need just a few elements out of metData xml element to map to my POJO fields.
There is also a chapter Partial marshalling/unmarshalling at http://camel.apache.org/jaxb.html but there is no JAVA DSL example (a must), nor how to annotate the pojo to 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();
    }
}
The XML (observation_si_latest.xml) comes in this 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>
I left out lots of elements of the metData elements for brevity. I want to map (amongs others) domain_title to my JPA annotated POJO's station field and later save it database, hopefully all in one smart and short Camel route.
The 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 out lots of fields and methods.
So the idea is to map the value of the *domain_title* to WeatherCurrent POJO's station field and to do so for each metData element and save a list of WeatherCurrent objects to database.
Any advice on the best way on how to implement this is welcome.
It turns out I had one wrong assumption of not being able to use the @XmlRootElement. The route and the test passes with success after I annotated the POJO and added jaxb.index file beside it. Will post the solution later or tomorrow as I am on a train now.
Hours later...
The JAXB annotations on the POJO (on top of JPA ones):
@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;
enabled me to get a list of WeatherCurrent Exchage objects. Just for test I routed each one to my EchoBean to print out one property:
.unmarshal(jaxbDataFormat).bean(EchoBean.class, "printWeatherStation")
and EchoBean:
public class EchoBean {
    public String printWeatherStation(WeatherCurrent weatherCurrent) {
        return weatherCurrent.getStation();
    }
}
nicely prints out the names of the weather stations with the log Camel component.
The one undocumented thing that bothered me was that I had to put this jaxb.index file next WeatherCurrent java source although at http://camel.apache.org/jaxb.html it clearly says that jaxb context is initialized with
DataFormat jaxb = new JaxbDataFormat("com.acme.model");
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With