Привязка дочернего объекта списка XmlElement к объекту Java с помощью Jackson XmlMapper - PullRequest
0 голосов
/ 10 апреля 2019

С учетом следующего xml:

<?xml version="1.0" encoding="utf-8"?>
<live_schedules>
    <title>This Schedule</title>
    <date>20190328</date>
    <link>/v2/schedule</link>
    <id>schedule</id>
    <updated>2019-03-28T21:51:41+0</updated>
    <schedule>
        <sport id="1" name="Football" link="/v2/sport/1">
            <league id="100" name="Alliance of American Football" link="/v2/league/100" />
            <league id="101" name="Alliance of American Football" link="/v2/league/101" />
        </sport>
    </schedule>
</live_schedules>

А также с учетом следующих классов:

LiveScheduleDto.java

package com.stackoverflow.dto;

import lombok.AllArgsConstructor;
import lombok.Data;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@Data
@AllArgsConstructor
@XmlRootElement(name = "live_schedule")
@XmlAccessorType(XmlAccessType.FIELD)
public class LiveScheduleWrapper {

    @XmlElement(name = "title")
    private String title;

    @XmlElement(name = "date")
    private String date;

    @XmlElement(name = "link")
    private String link;

    @XmlElement(name = "id")
    private String id;

    @XmlElement(name = "updated")
    private String updatedDate;

    @XmlElement(name = "schedule")
    private ScheduleDto schedule;
}

ScheduleDto.java

package com.stackoverflow.dto;

import lombok.AllArgsConstructor;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.List;

@AllArgsConstructor
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "schedule")
class ScheduleDto {

    @XmlElement(name = "sport")
    List<SportDto> sports;
}

SportDto.java

package com.stackoverflow.dto;

import lombok.AllArgsConstructor;
import lombok.Data;

import javax.xml.bind.annotation.*;
import java.util.List;

@Data
@AllArgsConstructor
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "sport")
public class SportDto {

    @XmlAttribute(name = "id")
    Integer id;

    @XmlAttribute(name = "name")
    String name;

    @XmlAttribute(name = "link")
    String link;

    @XmlElementWrapper(name = "league")
    List<LeagueDto> league;
}

LeagueDto.java

package com.stackoverflow.dto;

import lombok.AllArgsConstructor;

import javax.xml.bind.annotation.*;

@AllArgsConstructor
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "league")
public class LeagueDto {

    @XmlAttribute(name = "id")
    String id;

    @XmlAttribute(name = "name")
    String name;

    @XmlAttribute(name = "link")
    String link;
}

Адаптер, который выполняет сопоставление:

package com.stackoverflow.adaptors;

import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule;
import com.stackoverflow.dto.LiveScheduleWrapper;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;

import java.io.IOException;

public class ScheduleAdaptor {

    private final HttpClient httpClient;
    private final HttpGet httpGet;

    public ScheduleAdaptor(HttpClient httpClient, HttpGet httpGet) {
        this.httpClient = httpClient;
        this.httpGet = httpGet;
    }

    public HttpApiResponse<LiveScheduleWrapper> retrieveSchedule() {
        try {
            HttpResponse response = httpClient.execute(httpGet);
            XmlMapper mapper = new XmlMapper();
            JaxbAnnotationModule module = new JaxbAnnotationModule();
            mapper.registerModule(module);

            LiveScheduleWrapper schedule =
                    mapper.readValue(response.getEntity().getContent(), LiveScheduleWrapper.class);
            return new HttpApiResponse(response.getStatusLine().getStatusCode(), schedule);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}

Я вижу при запускеэто через анализатор связывает SportDto с LeagueDto, потому что я определил элемент <sport> как List.Это не то, что я ожидал.Вместо этого я ожидал, что он связывает Sport XmlElement с объектом SportDto, а затем с лигой - с вложенным объектом League, как я определил в моем примере.

Какой самый простой способ правильно связать элемент <sport> xmlсписок в SportDto и список элементов <league> xml в LeagueDto?

Я должен дать понять, что я использую Jackson s XmlMapper, а не JAXBContext

1 Ответ

0 голосов
/ 10 апреля 2019

Мне удалось это исправить.Моя проблема заключалась в том, что я использовал Jackson XmlMapper, который не так полнофункциональн, как JAXBContext библиотека ...

Я заменил свою функцию retrieveSchedule следующим:

public HttpApiResponse<LiveScheduleWrapper> retrieveSchedule() {
    try {
        HttpResponse response = httpClient.execute(httpGet);
        JAXBContext jc = JAXBContext.newInstance(LiveScheduleWrapper.class);
        Unmarshaller unmarshaller = jc.createUnmarshaller();
        LiveScheduleWrapper schedule = (LiveScheduleWrapper) unmarshaller.unmarshal(response.getEntity().getContent());
        return new HttpApiResponse(response.getStatusLine().getStatusCode(), schedule);
    } catch (JAXBException | IOException e) {
        e.printStackTrace();
    }
    return null;
}

Это решило мою проблему, потому что JAXBContext правильно распознает аннотации JAXB над XmlMapper.

...