1

让我从我的问题归结为什么开始。我正在使用 maven-jaxb2-plugin 从 XSD 模式生成一个名为 MyServiceResponse 的类。生成的 MyServiceResponse 类包含@XmlType具有空名称属性的注释。

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

    })

我想生成具有填充name属性或@XmlType完全没有注释的 MyServiceResponse 。这是否可以在 XJB 文件中使用自定义绑定或以其他方式?无论如何,如果可能的话,我想在生成过程中解决这个问题,因为每次运行 Maven 插件时,对 MyserviceResponse 的手动编辑都会被覆盖。

下面是一个演示我的实际问题的 Java 类。该类使用 XmlStreamReader 和 JAXB 从消息中的任何元素开始解组 XML 消息。'xml' 变量没有完全解组。'汽车' 属性保持不变null。这是因为xmlns="http://www.example.com/type"命名空间被 XmlStreamReader 复制到 Body 元素,而不是 Car 子元素。不知何故,JAXB 无法看到我希望它继续解组 Car 元素。(这里有个大问号)

我已经知道一些修复,但它们涉及手动更改 XSD 或 MyServiceResponse 类。

首先,我可以elementFormDefault="qualified"在 XSD 上进行设置,从中生成 MyServiceResponse 类、ObjectFactory 和 package-info.java。这可行,但它也会导致我的请求 XML 消息被编组为合格的名称空间,并且我将消息发送到的服务不接受这一点。此外,它需要对 XSD 进行更改,如果可能的话,我希望避免这样做。

其次,在 Body 和 Car @XmlType 注释上设置名称有效:@XmlType(name = "Body", propOrder = {})@XmlType(name = "Car", propOrder = {}). 但它涉及手动编辑 MyServiceResponse。

第三,删除@XmlType(name = "", propOrder = {})注释是可行的,但它也涉及到手动编辑 MyServiceResponse。

这是一个可复制粘贴的演示类:

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);
    }

}

我的 XSD:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://www.example.com/type"
           targetNamespace="http://www.example.com/type" elementFormDefault="qualified" >
    <xs:element name="serviceResponse" type="MyServiceResponse"/>
    <xs:complexType name="MyServiceResponse">
        <xs:all>
            <xs:element name="Body" minOccurs="0">
                <xs:complexType>
                    <xs:all>
                        <xs:element name="Car" minOccurs="0">
                            <xs:complexType>
                                <xs:all>
                                    <xs:element name="Brand" type="xs:string" minOccurs="0"/>
                                    <xs:element name="Color" type="xs:string" minOccurs="0"/>
                                </xs:all>
                            </xs:complexType>
                        </xs:element>
                    </xs:all>
                </xs:complexType>
            </xs:element>
        </xs:all>
    </xs:complexType>
</xs:schema>

添加:

这是开始解组时 XmlStreamReader 中的 XML。JAXB 解组 ServiceResponse 元素 Body,但不解组 Car。

<type:serviceResponse xmlns:type="http://www.example.com/type"> 
    <Body xmlns="http://www.example.com/type"> 
        <Car> 
            <Brand>Mitsubishi</Brand> 
            <Color>Red</Color> 
        </Car> 
    </Body> 
</type:serviceResponse>
4

1 回答 1

2

@XmlTypename 的属性为空,因为 Car 和 Body 是匿名类型。(http://docs.oracle.com/javaee/5/api/javax/xml/bind/annotation/XmlType.html

在全局命名空间中创建complexTypes并将它们用作type. element(小片段)

<xs:element name="Body" type="Body" minOccurs="0" />
<xs:complexType name="Body"> 

或者像这样创建一个 JAXB 绑定:https ://www.ibm.com/developerworks/library/ws-avoid-anonymous-types/#N100BB

转换后的 XSD:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://www.example.com/type"
    targetNamespace="http://www.example.com/type" elementFormDefault="unqualified" >

    <xs:element name="serviceResponse" type="MyServiceResponse"/>

    <xs:complexType name="MyServiceResponse">
        <xs:all>
            <xs:element name="Body" type="Body" minOccurs="0" />
        </xs:all>
    </xs:complexType>
    <xs:complexType name="Body">
        <xs:all>
            <xs:element name="Car" type="Car" minOccurs="0"/>
        </xs:all>
    </xs:complexType>
    <xs:complexType name="Car">
        <xs:all>
            <xs:element name="Brand" type="xs:string" minOccurs="0"/>
            <xs:element name="Color" type="xs:string" minOccurs="0"/>
        </xs:all>
    </xs:complexType>    
</xs:schema>
于 2017-03-29T16:52:44.163 回答