Страницы

Поиск по вопросам

суббота, 6 июля 2019 г.

Возможен ли реактивный маршалинг (marshaling) xml в java-объект?

Я делаю запрос на определенный сервис который отдаем мне очень медленно большой xml
Мне нужно не дожидаясь полного ответа документа начать читать и преобразовывать некоторые элементы xml в java-объекты через Jaxb и производить с ними не который операции
Как такое реализовать с помощью reactive spring и возможно ли?


Ответ

Попытался сделать максимально простой пример. Использовал java 9.
Исходные данные:
Xml вида:
Jack Green Ivan Ivanov
Класс в который будет маппится содержимое тега person
@XmlAccessorType(XmlAccessType.FIELD) private static class Person { @XmlElement private String name; @XmlElement private String surname;
@Override public String toString() { return String.format("Person{name=%s, surname=%s}", name, surname); } }
Теперь нам необходимо написать publisher который будет производить анмаршаллинг:
private static class MyPublisher extends SubmissionPublisher {
void run(String fileName) { try { XMLInputFactory xif = XMLInputFactory.newFactory(); StreamSource xml = new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName)); XMLStreamReader xsr = xif.createXMLStreamReader(xml); xsr.nextTag(); int count = Integer.parseInt(xsr.getAttributeValue(null, "count"));
for (int i = 0; i < count; i++) { xsr.nextTag(); JAXBContext jc = JAXBContext.newInstance(Person.class); Unmarshaller unmarshaller = jc.createUnmarshaller(); JAXBElement jaxbElement = unmarshaller.unmarshal(xsr, Person.class); Person person = jaxbElement.getValue(); submit(person); } } catch (Exception e) { throw new RuntimeException(e); } } }
Ничего сложного - читаем первый тег, из него получаем значением атрибута count. Далее в цикле читаем последующие теги, преобразуем в объекты класса Person и отправляем подписчиками
Subscriber может выглядить следующим образом:
public static class PrintSubscriber implements Flow.Subscriber { private Flow.Subscription subscription;
@Override public void onSubscribe(Flow.Subscription subscription) { this.subscription = subscription; subscription.request(1); }
@Override public void onNext(Person item) { System.out.println("Received item: " + item); subscription.request(1); }
@Override public void onError(Throwable error) { System.out.println("Error occurred: " + error.getMessage()); }
@Override public void onComplete() { System.out.println("PrintSubscriber is complete"); } }
Как заставить все это работать вместе? Очень просто - создаем сначала publisher, потом subscriber Одного подписываем на другово и запускаем метод run для разбора xml
MyPublisher publisher = new MyPublisher(); publisher.subscribe(new PrintSubscriber()); publisher.run("demo.xml"); TimeUnit.MINUTES.sleep(1); publisher.close();
Запуск
Как известно в java 9 ввели модули, работа с xml отсутствует в дефолтном модуле java.base, поэтому в настройках своего модуля потребуется прописать зависимости. Выглядит это примерно так module-info.java :
open module ru.izebit { requires java.xml; requires java.xml.bind; }
PS java.xml.bind - deprecated, но до java 10 пользоваться еще можно, потом удалят ☹️

Комментариев нет:

Отправить комментарий