Fails to unmarshal list of XML same elements having same name as parents elements using @XmlElementWrapper

ぃ、小莉子 提交于 2019-12-24 06:27:03

问题


I have a XML document like below and would like to perform unmarshalling against it

    <?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:sh="http://www.w3.org/2001/XMLSchema-instance">
    <SOAP-ENV:Body>
        <people xmlns="http://ccm.intra.bt.com/manageServiceFault/2006/06"
            xmlns:cds="http://capabilities.nat.bt.com/xsd/manageServiceFault/2010/06/Contact/Details"
            xmlns:sh="http://wsi.nat.bt.com/2005/06/StandardHeader/"
            xsi:schemaLocation="http://ccm.intra.bt.com/manageServiceFault/2006/06 MSF_5.0.xsd">
            <cds:address>
                <cds:Address>
                    <cds:postTown>London</cds:postTown>
                    <cds:postCode>WC2E 7AT</cds:postCode>
                    <cds:thoroughfareName>Bow Street</cds:thoroughfareName>
                    <cds:dependentLocality>local123</cds:dependentLocality>
                    <cds:county>London</cds:county>
                    <cds:thoroughfareNumber>30-34</cds:thoroughfareNumber>
                    <cds:subPremise>2nd Floor</cds:subPremise>
                    <cds:buildingName>BT tower</cds:buildingName>
                    <cds:buildingNumber>Lot 1234</cds:buildingNumber>
                    <cds:locality>London</cds:locality>
                    <cds:premise>Covent Garden Exchange</cds:premise>
                    <cds:dependentThoroughfare>345</cds:dependentThoroughfare>
                    <cds:poBox>PO1234</cds:poBox>
                </cds:Address>
                <cds:Address>
                    <cds:postTown>New York</cds:postTown>
                    <cds:postCode>WC2E 7AT</cds:postCode>
                    <cds:thoroughfareName>Bow Street</cds:thoroughfareName>
                    <cds:dependentLocality>local123</cds:dependentLocality>
                    <cds:county>US</cds:county>
                    <cds:thoroughfareNumber>30-34</cds:thoroughfareNumber>
                    <cds:subPremise>2nd Floor</cds:subPremise>
                    <cds:buildingName>BT tower</cds:buildingName>
                    <cds:buildingNumber>Lot 1234</cds:buildingNumber>
                    <cds:locality>US</cds:locality>
                    <cds:premise>Covent Garden Exchange</cds:premise>
                    <cds:dependentThoroughfare>345</cds:dependentThoroughfare>
                    <cds:poBox>PO1234</cds:poBox>
                </cds:Address>
                <cds:country>
                    <cds:name>UK</cds:name>
                </cds:country>
                <cds:country>
                    <cds:name>US</cds:name>
                </cds:country>
            </cds:address>
        </people>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Notice that element address contains one or more than one Address and Country elements. Both address and Address are same same just only the A difference. Below are my domain classes

People2.java

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 javax.xml.bind.annotation.XmlType;

@XmlRootElement(name = "people")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(namespace = "http://capabilities.nat.bt.com/xsd/manageServiceFault/2010/06/Contact/Details")
public class People2 {

    @XmlElement(name = "address")
    private Addresses addresses;

    public Addresses getAddresses() {
        return addresses;
    }

    public void setAddresses(Addresses addresses) {
        this.addresses = addresses;
    }

}

Addresses.java

import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlType;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(namespace = "http://capabilities.nat.bt.com/xsd/manageServiceFault/2010/06/Contact/Details")
public class Addresses {

    @XmlElementWrapper(name = "address")
    @XmlElement(name = "Address")
    private List<Address> address;

    @XmlElementWrapper(name = "address")
    @XmlElement(name = "country")
    private List<Country> country;

    public Addresses() {
        address = new ArrayList<Address>();
        country = new ArrayList<Country>();
    }

    public List<Address> getAddress() {
        return address;
    }

    public void setAddress(List<Address> address) {
        this.address = address;
    }

    public List<Country> getCountry() {
        return country;
    }

    public void setCountry(List<Country> country) {
        this.country = country;
    }

}

and below is my main code to unmarshal the XML

import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;

public class Demo2 {

    public static void main(String[] args) throws FileNotFoundException, XMLStreamException, JAXBException,
            IllegalAccessException, IllegalArgumentException, InvocationTargetException, IntrospectionException {

        XMLInputFactory xif = XMLInputFactory.newInstance();
        XMLStreamReader xsr = xif.createXMLStreamReader(new FileReader("./xml/Testing2.xml"));

        JAXBContext jc = JAXBContext.newInstance(People2.class);
        Unmarshaller unmarshaller = jc.createUnmarshaller();

        xsr.nextTag();
        System.out.println("Current XML element: " + xsr.getLocalName());

        xsr.nextTag();
        System.out.println("Current XML element: " + xsr.getLocalName());

        int tag = xsr.nextTag();
        if (tag == XMLStreamConstants.START_ELEMENT) {
            System.out.println("Current XML element: " + xsr.getLocalName());

            People2 people = (People2) unmarshaller.unmarshal(xsr);

            for (PropertyDescriptor propertyDescriptor : Introspector.getBeanInfo(People2.class, Object.class)
                    .getPropertyDescriptors()) {
                Method method = propertyDescriptor.getReadMethod();
                System.out.println("Class name: " + people.getClass().getSimpleName() + ", Method: " + method.getName()
                        + ", Value: " + method.invoke(people));
            }

            Addresses addresses = people.getAddresses();
            for (PropertyDescriptor propertyDescriptor : Introspector.getBeanInfo(Addresses.class, Object.class)
                    .getPropertyDescriptors()) {
                Method method = propertyDescriptor.getReadMethod();
                System.out.println("Class name: " + addresses.getClass().getSimpleName() + ", Method: "
                        + method.getName() + ", Value: " + method.invoke(addresses));

            }

        }
    }

}

Problem is, when printing methods in Addresses, value of getAddress and getCountry returns null like below. It seems the binding is not happening.

Current XML element: Envelope
Current XML element: Body
Current XML element: people
Class name: People2, Method: getAddresses, Value: com.bt.platform.automation.domain.Addresses@433c675d
Class name: Addresses, Method: getAddress, Value: []
Class name: Addresses, Method: getCountry, Value: []

If I remove this @XmlElementWrapper(name = "address") in Addresses.java, it works fine like below

Current XML element: Envelope
Current XML element: Body
Current XML element: people
Class name: People2, Method: getAddresses, Value: com.bt.platform.automation.domain.Addresses@2e817b38
Class name: Addresses, Method: getAddress, Value: [com.bt.platform.automation.domain.Address@c4437c4, com.bt.platform.automation.domain.Address@433c675d]
Class name: Addresses, Method: getCountry, Value: [com.bt.platform.automation.domain.Country@3f91beef, com.bt.platform.automation.domain.Country@1a6c5a9e]

Cany anyone please help why is it not working as expected if I don't remove @XmlElementWrapper(name = "address")? I have referred to this post - http://blog.bdoughan.com/2010/09/jaxb-collection-properties.html but it doesn't seems working for my code.


回答1:


I think you're misunderstanding what @XmlElementWrapper is used for.

For the sake of the exemple, let's say that your address element only contains Address elements.

Then you could use the following code, and remove the necessity of your Adresses class :

@XmlRootElement(name = "people")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(namespace = "http://capabilities.nat.bt.com/xsd/manageServiceFault/2010/06/Contact/Details")
public class People2 {

    @XmlElement(name = "Address")
    @XmlElementWrapper(name = "address")
    private List<Address> addresses;

    public List<Address> getAddresses() {
        return addresses;
    }

    public void setAddresses(List<Address> addresses) {
        this.addresses = addresses;
    }

}

@XmlElementWrapper exists for the sake of this, as we tend to put a wrapper element around a list of given elements, and thus it would force to use an intermediary class.



来源:https://stackoverflow.com/questions/44364754/fails-to-unmarshal-list-of-xml-same-elements-having-same-name-as-parents-element

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!