Запрет генерации пустой аннотации @XmlType из XSD с помощью JAXB

Позвольте мне начать с того, к чему сводится мой вопрос. Я генерирую класс с именем MyServiceResponse из схемы XSD, используя плагин maven-jaxb2-. Результирующий класс MyServiceResponse содержит @XmlType аннотации с пустым атрибутом имени.

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

    })

Я хотел бы либо сгенерировать MyServiceResponse с заполненным name атрибуты ИЛИ без @XmlType аннотации в целом. Возможно ли это с помощью пользовательской привязки в файле XJB или каким-либо другим способом? В любом случае, я хочу решить эту проблему во время генерации, если это возможно, потому что ручное редактирование MyserviceResponse будет перезаписываться при каждом запуске плагина Maven.

Ниже приведен класс Java, который демонстрирует мою реальную проблему. Класс использует XmlStreamReader и JAXB для отмены сортировки сообщений XML, начиная с любого элемента в сообщении. Переменная 'xml' не полностью разбирается. Свойство "автомобиль" остается null, Это происходит потому, что xmlns="http://www.example.com/type" Пространство имен копируется в элемент Body XmlStreamReader, но не в дочерний элемент 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>

Добавлено:

Это тот XML, который находится в XmlStreamReader, когда он начинает демаршаллинг. 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>

1 ответ

@XmlType Атрибут name пуст, потому что 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/

Преобразованный 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>
Другие вопросы по тегам