JAXB / EclipseLink: Unmarshal параметризованный список неоднозначных объектов - PullRequest
0 голосов
/ 30 января 2020

Вот два примера XML, который я пытаюсь разобрать с помощью JAXB / EclipseLink:

Пример. 1:

<?xml version="1.0" encoding="ISO-8859-1"?>
<responseMessage requestedService="warehouses.activeProducts" responseStatus="1" >
    <responseBody>
        <entities name="Product">
            <entity>
                <PRODUCTID>09941234504</PRODUCTID>
                <PRODUCTDESCRIPTION>
                    <![CDATA[SOME PRODUCT DESCRIPTION 1]]>
                </PRODUCTDESCRIPTION>
                <ACTIVE>
                    <![CDATA[S]]>
                </ACTIVE>
            </entity>
            <entity>
                <PRODUCTID>09941234182</PRODUCTID>
                <PRODUCTDESCRIPTION>
                    <![CDATA[SOME PRODUCT DESCRIPTION 2]]>
                </PRODUCTDESCRIPTION>
                <ACTIVE>
                    <![CDATA[S]]>
                </ACTIVE>
            </entity>
        </entities>
    </responseBody>
</responseMessage>

Пример. 2:

<?xml version="1.0" encoding="ISO-8859-1"?>
<responseMessage requestedService="warehouses.availableLocations" responseStatus="1" >
    <responseBody>
        <entities name="Location">
            <entity>
                <LOCATIONID>10925243325</LOCATIONID>
                <ACTIVE>
                    <![CDATA[S]]>
                </ACTIVE>
            </entity>
            <entity>
                <LOCATIONID>10925243325</LOCATIONID>
                <ACTIVE>
                    <![CDATA[S]]>
                </ACTIVE>
            </entity>
        </entities>
    </responseBody>
</responseMessage>

Мы имеем представление о том, что находится внутри списка <entities></entities>, из-за его атрибута name (name="Product" и name="Location").

Моя реализация что-то вроде этого:

serviceCallResponse_products = ... input stream of the service's call for products...
serviceCallResponse_locations = ... input stream of the service's call for locations...

Class[] classes = new Class[]{
    ResponseMessage.class, // @XmlRootElement(name = "responseMessage")
    ResponseBody.class,  // @XmlRootElement(name = "responseBody")
    Entities.class // @XmlRootElement(name = "entities") - the list wrapper

    Product.class, // @XmlRootElement(name = "entity")
    Location.class, // @XmlRootElement(name = "entity")
};

JAXBContext createContext = JAXBContext.newInstance(classes);
Unmarshaller createUnmarshaller = createContext.createUnmarshaller();


// This works!
ResponseMessage<Location> = r = (ResponseMessage<Location>) createUnmarshaller
                .unmarshal(serviceCallResponse_locations);

// This does not work. I get a ResponseMessage<Location> instead of ResponseMessage<Product>
ResponseMessage<Product> = r = (ResponseMessage<Product>) createUnmarshaller
                .unmarshal(serviceCallResponse_products);

и вот мои объекты:

@XmlRootElement(name = "responseMessage")
public class ResponseMessage<T> {

    public ResponseMessage() {
        responseBody = new ResponseBody<>();
    }

    @XmlElement
    private ResponseBody<T> responseBody;

}

@XmlRootElement(name = "responseBody")
public class ResponseBody<T> {

    public ResponseBody() {
        this.entities = new Entities<>();
    }

    @XmlElement
    private Entities<T> entities;

}

@XmlRootElement(name = "entities")
public class Entities<T> {

    public Entities() {
        this.entityList = new ArrayList<T>();
    }

    private String name;

    List<T> entityList;

    @XmlAttribute
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @XmlAnyElement(lax = true)
    public List<T> getEntityList() {
        return entityList;
    }

    public void setEntityList(List<T> entityList) {
        this.entityList = entityList;
    }

}

@XmlRootElement(name = "entity")
public class Product {

    @XmlElement(name = "PRODUCTID")
    private String productId;

    @XmlElement(name = "PRODUCTDESCRIPTION")
    private String productDescription;

    @XmlElement(name = "ACTIVE")
    private String active;

}

@XmlRootElement(name = "entity")
public class Location {

    @XmlElement(name = "LOCATIONID")
    private String productId;

    @XmlElement(name = "ACTIVE")
    private String active;

}

Проблема заключается в том, как правильно демаршировать список объектов в список объектов параметризованного типа, либо Product или Location. Поскольку и Product, и Location имеют одно и то же имя элемента («сущность»), JAXB будет анализировать сопоставленный элемент xml с последним зарегистрированным (в данном случае Location).

Несмотря на то, что я использую JAXB непосредственно здесь, мое приложение использует OpenFeign для выполнения запросов и оборачивает JaxB в класс кодировщика / декодера.

Есть ли лучший (или правильный) способ сопоставить этот сценарий / сущности?

Есть ли какой-нибудь способ "подсказки" JaxB для создания экземпляра объекта в зависимости от атрибута его родителя ("name")?

Спасибо!

...