Как создать маршрут Camel, который принимает XML и привязывает некоторые данные к аннотированному JPA POJO? - PullRequest
8 голосов
/ 14 марта 2012

Я новичок в Apache Camel и пробное тестирование, так что вот оно ...

У меня есть XML без XSD-схемы, на который я не могу повлиять. Дочерние элементы этого XML содержат данные, которые я хочу привязать к своему бизнес-процессу. Этот POJO (WeatherCurrent) уже аннотирован JPA, и я подумывал добавить аннотацию JAXB, чтобы разделенный XML можно было сопоставить с моим POJO.

Поскольку у этого XML есть корневой элемент, и я хочу только его дочерние элементы (metData), у меня есть проблема, как аннотировать мой POJO, поскольку я не могу использовать @ XmlRootElement.

Это частично описано здесь: http://camel.apache.org/splitter.html при Потоковая передача больших полезных XML-данных с использованием языка Tokenizer глава. Мой POJO в этом примере похож на элемент order xml. Мне нужно всего несколько элементов из элемента metData xml для сопоставления с моими полями POJO.

Существует также глава Частичное маршалинг / демаршаллинг в http://camel.apache.org/jaxb.html, но нет ни примера JAVA DSL (обязательно), ни того, как аннотировать pojo для работы с фрагментами XML.

Пока у меня есть этот тестовый код:

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 (наблюдение_si_latest.xml) имеет следующую форму:

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

Я упустил множество элементов metData для краткости. Я хочу сопоставить (среди прочего) domain_title с полем станции POJO, аннотированным в JPA, а затем сохранить его в базе данных, надеюсь, все по одному умному и короткому маршруту Camel.

POJO (пока нет комментариев JAXB):

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

}

Я также пропустил множество полей и методов.

Таким образом, идея состоит в том, чтобы сопоставить значение * domain_title * с полем WeatherCurrent POJO station , сделать это для каждого элемента metData и сохранить список объектов WeatherCurrent в базе данных.

Любые советы о том, как это реализовать, приветствуются.

1 Ответ

3 голосов
/ 14 марта 2012

Оказывается, у меня было одно неверное предположение, что я не могу использовать @XmlRootElement.Маршрут и тест пройдены успешно после того, как я аннотировал POJO и добавил файл jaxb.index рядом с ним.Опубликуйте решение позже или завтра, так как я сейчас в поезде.

Несколько часов спустя ...

Аннотации JAXB на POJO (поверх 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;

позволил мне получить список объектов WeatherCurrent Exchage.Просто для проверки я перенаправил каждое из них в свой EchoBean, чтобы распечатать одно свойство:

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

и EchoBean:

public class EchoBean {

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

, красиво распечатывая названия метеостанций с журналом Camelcomponent.

Одной недокументированной вещью, которая беспокоила меня, было то, что я должен был поместить этот файл jaxb.index в следующий Java-источник WeatherCurrent, хотя в http://camel.apache.org/jaxb.html он ясно говорит, что контекст jaxb инициализируется с

DataFormat jaxb = new JaxbDataFormat("com.acme.model");
...