繁体   English   中英

从XmlStreamReader解组JAXB会导致空对象

[英]JAXB unmarshalling from XmlStreamReader results in null object

我创建了一个用于解组XML消息的Java过程,其中可以提供“ startTag”以在消息中的特定元素上开始解组。 我使用XMLStreamReader进行了选择。

下面是我遇到的问题的完整可复制复制的演示。 我需要使用“ xml”消息。 不幸的是,它会在结果中产生一个null汽车对象,而“ xmlStripped”消息会产生一个完全未编组的结果。

我将问题隔离到<response>元素中的xmlns="http://www.example.com/type"命名空间。 当我删除它时,“ xml”已正确解组。

无法控制 XML。 我需要使用'xml'变量。 我对XSD / ObjectFactory 几乎没有控制权,所以我的第一步是在解组过程中寻找解决方案。

如果您知道失败的原因以及解决方案,请告诉我。 谢谢!

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.*;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import java.io.Reader;
import java.io.StringReader;

public class XmlStreamReaderUnmarshallingTest {

    private static JAXBContext jaxbContext;

    static {
        try {
            jaxbContext = JAXBContext.newInstance(ObjectFactory.class);
        } catch (JAXBException e) {
            e.printStackTrace();
        }
    }

    private static String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
            "<soapenv:Envelope xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" \n" +
            "\txmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" \n" +
            "\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n" +
            "\t<soapenv:Body>\n" +
            "\t\t<response xmlns=\"http://www.example.com/type\">\n" +
            "\t\t\t<type:serviceResponse xmlns:type=\"http://www.example.com/type\">\n" +
            "\t\t\t\t<Body>\n" +
            "\t\t\t\t\t<Car>\n" +
            "\t\t\t\t\t\t<Brand>Mitsubishi</Brand>\n" +
            "\t\t\t\t\t\t<Color>Red</Color>\n" +
            "\t\t\t\t\t</Car>\n" +
            "\t\t\t\t</Body>\n" +
            "\t\t\t</type:serviceResponse>\n" +
            "\t\t</response>\n" +
            "\t</soapenv:Body>\n" +
            "</soapenv:Envelope>";


    private static String xmlStripped = "<type:serviceResponse xmlns:type=\"http://www.example.com/type\">\n" +
            "\t\t\t\t<Body>\n" +
            "\t\t\t\t\t<Car>\n" +
            "\t\t\t\t\t\t<Brand>Mitsubishi</Brand>\n" +
            "\t\t\t\t\t\t<Color>Red</Color>\n" +
            "\t\t\t\t\t</Car>\n" +
            "\t\t\t\t</Body>\n" +
            "\t\t\t</type:serviceResponse>";


    public static void main(String[] args) throws JAXBException, XMLStreamException {
        readXml(xml, "serviceResponse");
        readXml(xmlStripped, "serviceResponse");
    }

    private static void readXml(String inputXml, String startFromElement) throws JAXBException, XMLStreamException {

        final XMLInputFactory xmlInputFactory = XMLInputFactory.newFactory();
        final Reader reader = new StringReader(inputXml);
        final XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(reader);
        final XMLStreamReader streamReader = skipToElement(xmlStreamReader, startFromElement);
        final MyServiceResponse serviceResponse = (MyServiceResponse) unmarshal(streamReader);

        if(serviceResponse.getBody().getCar() == null) {
            System.out.println("It didn't work :-(");
        } else {
            System.out.println("It worked");
        }
    }

    private static XMLStreamReader skipToElement(final XMLStreamReader xsr, final String startAtElement) throws XMLStreamException {
        while (startAtElement != null && xsr.hasNext()) {
            xsr.next();
            if (xsr.hasName()) {
                final String name = xsr.getName().getLocalPart();
                if (name.equals(startAtElement)) {
                    return xsr;
                }
            }
        }

        throw new IllegalArgumentException(String.format("Could not find element %s in response", startAtElement));
    }

    private static Object unmarshal(final XMLStreamReader xsr) throws JAXBException {
        final Object entity = unmarshaller(jaxbContext).unmarshal(xsr);
        return (entity instanceof JAXBElement ? ((JAXBElement) entity).getValue() : entity);
    }

    // Create unmarshaller every time
    private static Unmarshaller unmarshaller(JAXBContext context) throws JAXBException {

        return context.createUnmarshaller();

    }
}


@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "MyServiceResponse", propOrder = {

})
class MyServiceResponse {

    @XmlElement(name = "Body")
    protected MyServiceResponse.Body body;

    /**
     * Gets the value of the body property.
     *
     * @return
     *     possible object is
     *     {@link MyServiceResponse.Body }
     *
     */
    public MyServiceResponse.Body getBody() {
        return body;
    }

    /**
     * Sets the value of the body property.
     *
     * @param value
     *     allowed object is
     *     {@link MyServiceResponse.Body }
     *
     */
    public void setBody(MyServiceResponse.Body value) {
        this.body = value;
    }


    /**
     * <p>Java class for anonymous complex type.
     *
     * <p>The following schema fragment specifies the expected content contained within this class.
     *
     * <pre>
     * &lt;complexType&gt;
     *   &lt;complexContent&gt;
     *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&gt;
     *       &lt;all&gt;
     *         &lt;element name="Car" minOccurs="0"&gt;
     *           &lt;complexType&gt;
     *             &lt;complexContent&gt;
     *               &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&gt;
     *                 &lt;all&gt;
     *                   &lt;element name="Brand" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/&gt;
     *                   &lt;element name="Color" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/&gt;
     *                 &lt;/all&gt;
     *               &lt;/restriction&gt;
     *             &lt;/complexContent&gt;
     *           &lt;/complexType&gt;
     *         &lt;/element&gt;
     *       &lt;/all&gt;
     *     &lt;/restriction&gt;
     *   &lt;/complexContent&gt;
     * &lt;/complexType&gt;
     * </pre>
     *
     *
     */
    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "", propOrder = {

    })
    public static class Body {

        @XmlElement(name = "Car")
        protected MyServiceResponse.Body.Car car;

        /**
         * Gets the value of the car property.
         *
         * @return
         *     possible object is
         *     {@link MyServiceResponse.Body.Car }
         *
         */
        public MyServiceResponse.Body.Car getCar() {
            return car;
        }

        /**
         * Sets the value of the car property.
         *
         * @param value
         *     allowed object is
         *     {@link MyServiceResponse.Body.Car }
         *
         */
        public void setCar(MyServiceResponse.Body.Car value) {
            this.car = value;
        }


        /**
         * <p>Java class for anonymous complex type.
         *
         * <p>The following schema fragment specifies the expected content contained within this class.
         *
         * <pre>
         * &lt;complexType&gt;
         *   &lt;complexContent&gt;
         *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&gt;
         *       &lt;all&gt;
         *         &lt;element name="Brand" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/&gt;
         *         &lt;element name="Color" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/&gt;
         *       &lt;/all&gt;
         *     &lt;/restriction&gt;
         *   &lt;/complexContent&gt;
         * &lt;/complexType&gt;
         * </pre>
         *
         *
         */
        @XmlAccessorType(XmlAccessType.FIELD)
        @XmlType(name = "", propOrder = {

        })
        public static class Car {

            @XmlElement(name = "Brand")
            protected String brand;
            @XmlElement(name = "Color")
            protected String color;

            /**
             * Gets the value of the brand property.
             *
             * @return
             *     possible object is
             *     {@link String }
             *
             */
            public String getBrand() {
                return brand;
            }

            /**
             * Sets the value of the brand property.
             *
             * @param value
             *     allowed object is
             *     {@link String }
             *
             */
            public void setBrand(String value) {
                this.brand = value;
            }

            /**
             * Gets the value of the color property.
             *
             * @return
             *     possible object is
             *     {@link String }
             *
             */
            public String getColor() {
                return color;
            }

            /**
             * Sets the value of the color property.
             *
             * @param value
             *     allowed object is
             *     {@link String }
             *
             */
            public void setColor(String value) {
                this.color = value;
            }

        }

    }

}


@XmlRegistry
class ObjectFactory {

    private final static QName _ServiceResponse_QNAME = new QName("http://www.example.com/type", "serviceResponse");

    /**
     * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: com.example.type
     *
     */
    public ObjectFactory() {
    }

    /**
     * Create an instance of {@link MyServiceResponse }
     *
     */
    public MyServiceResponse createMyServiceResponse() {
        return new MyServiceResponse();
    }

    /**
     * Create an instance of {@link MyServiceResponse.Body }
     *
     */
    public MyServiceResponse.Body createMyServiceResponseBody() {
        return new MyServiceResponse.Body();
    }

    /**
     * Create an instance of {@link MyServiceResponse.Body.Car }
     *
     */
    public MyServiceResponse.Body.Car createMyServiceResponseBodyCar() {
        return new MyServiceResponse.Body.Car();
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link MyServiceResponse }{@code >}}
     *
     */
    @XmlElementDecl(namespace = "http://www.example.com/type", name = "serviceResponse")
    public JAXBElement<MyServiceResponse> createServiceResponse(MyServiceResponse value) {
        return new JAXBElement<MyServiceResponse>(_ServiceResponse_QNAME, MyServiceResponse.class, null, value);
    }

}

您可以通过创建package-info.java并添加以下内容来为模型设置elementFormDefault =“ qualified”

package-info.java

@XmlSchema(namespace="http://www.example.com/type", elementFormDefault=XmlNsForm.QUALIFIED)

package mypkg;

import javax.xml.bind.annotation.*;

这将允许您的常规XML,而不是“剥离的” XML,可以工作。 除了外部包装元素的“剥离”之外,两者之间的区别在于原始XML具有默认名称空间集,而剥离的XML没有。

在@XmlType批注上设置name属性:

@XmlType(name = "Body", propOrder = {

})
public static class Body { ... }

@XmlType(name = "Car", propOrder = {

})
public static class Car { ... }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM