Смешанный контент для JAXB, не работающий с WSDL

Я использую NetBeans, и у меня есть два проекта:

  • Модуль EJB для создания веб-сервиса и его развертывания в GlassFish
  • Простой клиент консоли для тестирования и использования этого веб-сервиса

Для веб-службы я использую XSD со смешанными элементами контента. Добавление файла привязки для импорта JAXB с использованием следующего кода:

<?xml version="1.0" encoding="UTF-8"?>
<jaxb:bindings
 xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
 xmlns:xjc= "http://java.sun.com/xml/ns/jaxb/xjc" jaxb:extensionBindingPrefixes="xjc"
 jaxb:version="2.0">
  <jaxb:globalBindings generateMixedExtensions="true"/>
</jaxb:bindings>

Он сгенерировал этот код:

@XmlMixed
@OverrideAnnotationOf
protected List<Serializable> contentOverrideForED;

Я могу жить с этим сгенерированным кодом, хотя он не идеален.

Моя проблема с клиентом, для которого я добавил ссылку на веб-службу для моего сгенерированного и развернутого веб-сервиса, запущенного просто на локальном хосте.

Использование одного и того же файла привязки в WSDL Customization: External Binding File не дает код content и не использует его напрямую в качестве опции для Wsimport и не использует его как Jaxb option. У меня такое чувство, что эта настройка проигнорирована каким-то образом, но как?

И почему исходное поколение JAXB включает его и почему его не использует wsimport? Я немного озадачен здесь.

Ответы

Ответ 1

Возможно, вы захотите использовать Eclipse для генерации того, что вам нужно. Несмотря на то, что xsd и wsdl, которые вы используете, не включены в вопрос, я придумал простой пример, который, похоже, работает. Я не использовал файл привязок, мастер в Eclipse выбрал тот факт, что смешанный был необходим, потому что mixed - "true" в XSD (может попробовать попробовать без привязки):

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

<xs:element name="letter">
  <xs:complexType mixed="true">
    <xs:sequence>
      <xs:element name="name" type="xs:string"/>
      <xs:element name="orderid" type="xs:positiveInteger"/>
      <xs:element name="shipdate" type="xs:date"/>
    </xs:sequence>
  </xs:complexType>
</xs:element>

</xs:schema>

WSDL:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://www.example.org/NewWSDLFile/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="NewWSDLFile" targetNamespace="http://www.example.org/NewWSDLFile/" xmlns:xsd1="http://www.example.org/NewXMLSchema">
  <wsdl:types>
    <xsd:schema targetNamespace="http://www.example.org/NewWSDLFile/">
      <xsd:element name="NewOperation">
        <xsd:complexType>
          <xsd:sequence>
            <xsd:element name="in" type="xsd:string"/>
          </xsd:sequence>
        </xsd:complexType>
      </xsd:element>
      <xsd:element name="NewOperationResponse">
        <xsd:complexType>
          <xsd:sequence>
            <xsd:element name="out" type="xsd:string"/>
          </xsd:sequence>
        </xsd:complexType>
      </xsd:element>
    </xsd:schema>
    <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <xsd:import namespace="http://www.example.org/NewXMLSchema"
            schemaLocation="NewXMLSchema.xsd">
        </xsd:import></xsd:schema></wsdl:types>
  <wsdl:message name="NewOperationRequest">
    <wsdl:part element="xsd1:letter" name="parameters"/>
  </wsdl:message>
  <wsdl:message name="NewOperationResponse">
    <wsdl:part element="tns:NewOperationResponse" name="parameters"/>
  </wsdl:message>
  <wsdl:portType name="NewWSDLFile">
    <wsdl:operation name="NewOperation">
      <wsdl:input message="tns:NewOperationRequest"/>
      <wsdl:output message="tns:NewOperationResponse"/>
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="NewWSDLFileSOAP" type="tns:NewWSDLFile">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="NewOperation">
      <soap:operation soapAction="http://www.example.org/NewWSDLFile/NewOperation"/>
      <wsdl:input>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="NewWSDLFile">
    <wsdl:port binding="tns:NewWSDLFileSOAP" name="NewWSDLFileSOAP">
      <soap:address location="http://www.example.org/"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

Первичная Java:

    //
    // Generated By:JAX-WS RI IBM 2.2.1-11/28/2011 08:28 AM(foreman)- (JAXB RI IBM 2.2.3-11/28/2011 06:21 AM(foreman)-)
    //


    package org.example.newwsdlfile;

    import javax.jws.WebMethod;
    import javax.jws.WebParam;
    import javax.jws.WebResult;
    import javax.jws.WebService;
    import javax.jws.soap.SOAPBinding;
    import javax.xml.bind.annotation.XmlSeeAlso;
    import org.example.newxmlschema.Letter;

    @WebService(name = "NewWSDLFile", targetNamespace = "http://www.example.org/NewWSDLFile/")
    @SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
    @XmlSeeAlso({
        org.example.newwsdlfile.ObjectFactory.class,
        org.example.newxmlschema.ObjectFactory.class
    })
    public interface NewWSDLFile {


        /**
         * 
         * @param parameters
         * @return
         *     returns org.example.newwsdlfile.NewOperationResponse
         */
        @WebMethod(operationName = "NewOperation", action = "http://www.example.org/NewWSDLFile/NewOperation")
        @WebResult(name = "NewOperationResponse", targetNamespace = "http://www.example.org/NewWSDLFile/", partName = "parameters")
        public NewOperationResponse newOperation(
            @WebParam(name = "letter", targetNamespace = "http://www.example.org/NewXMLSchema", partName = "parameters")
            Letter parameters);

    }

Реализация:

    package org.example.newwsdlfile;

    import java.net.URL;

    import javax.xml.namespace.QName;
    import javax.xml.transform.Source;
    import javax.xml.ws.BindingProvider;
    import javax.xml.ws.Dispatch;
    import javax.xml.ws.Service;
    import javax.xml.ws.soap.SOAPBinding;
    import org.example.newxmlschema.Letter;

    public class NewWSDLFileSOAPProxy{

        protected Descriptor _descriptor;

        public class Descriptor {
            private org.example.newwsdlfile.NewWSDLFile_Service _service = null;
            private org.example.newwsdlfile.NewWSDLFile _proxy = null;
            private Dispatch<Source> _dispatch = null;

            public Descriptor() {
                init();
            }

            public Descriptor(URL wsdlLocation, QName serviceName) {
                _service = new org.example.newwsdlfile.NewWSDLFile_Service(wsdlLocation, serviceName);
                initCommon();
            }

            public void init() {
                _service = null;
                _proxy = null;
                _dispatch = null;
                _service = new org.example.newwsdlfile.NewWSDLFile_Service();
                initCommon();
            }

            private void initCommon() {
                _proxy = _service.getNewWSDLFileSOAP();
            }

            public org.example.newwsdlfile.NewWSDLFile getProxy() {
                return _proxy;
            }

            public Dispatch<Source> getDispatch() {
                if (_dispatch == null ) {
                    QName portQName = new QName("http://www.example.org/NewWSDLFile/", "NewWSDLFileSOAP");
                    _dispatch = _service.createDispatch(portQName, Source.class, Service.Mode.MESSAGE);

                    String proxyEndpointUrl = getEndpoint();
                    BindingProvider bp = (BindingProvider) _dispatch;
                    String dispatchEndpointUrl = (String) bp.getRequestContext().get(BindingProvider.ENDPOINT_ADDRESS_PROPERTY);
                    if (!dispatchEndpointUrl.equals(proxyEndpointUrl))
                        bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, proxyEndpointUrl);
                }
                return _dispatch;
            }

            public String getEndpoint() {
                BindingProvider bp = (BindingProvider) _proxy;
                return (String) bp.getRequestContext().get(BindingProvider.ENDPOINT_ADDRESS_PROPERTY);
            }

            public void setEndpoint(String endpointUrl) {
                BindingProvider bp = (BindingProvider) _proxy;
                bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpointUrl);

                if (_dispatch != null ) {
                    bp = (BindingProvider) _dispatch;
                    bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpointUrl);
                }
            }

            public void setMTOMEnabled(boolean enable) {
                SOAPBinding binding = (SOAPBinding) ((BindingProvider) _proxy).getBinding();
                binding.setMTOMEnabled(enable);
            }
        }

        public NewWSDLFileSOAPProxy() {
            _descriptor = new Descriptor();
            _descriptor.setMTOMEnabled(false);
        }

        public NewWSDLFileSOAPProxy(URL wsdlLocation, QName serviceName) {
            _descriptor = new Descriptor(wsdlLocation, serviceName);
            _descriptor.setMTOMEnabled(false);
        }

        public Descriptor _getDescriptor() {
            return _descriptor;
        }

        public NewOperationResponse newOperation(Letter parameters) {
            return _getDescriptor().getProxy().newOperation(parameters);
        }

    }

Класс "Letter":

    //
    // Generated By:JAX-WS RI IBM 2.2.1-11/28/2011 08:28 AM(foreman)- (JAXB RI IBM 2.2.3-11/28/2011 06:21 AM(foreman)-)
    //


    package org.example.newxmlschema;

    import java.io.Serializable;
    import java.math.BigInteger;
    import java.util.ArrayList;
    import java.util.List;
    import javax.xml.bind.JAXBElement;
    import javax.xml.bind.annotation.XmlAccessType;
    import javax.xml.bind.annotation.XmlAccessorType;
    import javax.xml.bind.annotation.XmlElementRef;
    import javax.xml.bind.annotation.XmlElementRefs;
    import javax.xml.bind.annotation.XmlMixed;
    import javax.xml.bind.annotation.XmlRootElement;
    import javax.xml.bind.annotation.XmlType;
    import javax.xml.datatype.XMLGregorianCalendar;


    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "", propOrder = {
        "content"
    })
    @XmlRootElement(name = "letter")
    public class Letter {

        @XmlElementRefs({
            @XmlElementRef(name = "name", namespace = "http://www.example.org/NewXMLSchema", type = JAXBElement.class),
            @XmlElementRef(name = "shipdate", namespace = "http://www.example.org/NewXMLSchema", type = JAXBElement.class),
            @XmlElementRef(name = "orderid", namespace = "http://www.example.org/NewXMLSchema", type = JAXBElement.class)
        })
        @XmlMixed
        protected List<Serializable> content;


        public List<Serializable> getContent() {
            if (content == null) {
                content = new ArrayList<Serializable>();
            }
            return this.content;
        }

    }

Ответ 2

Отличный вопрос! Я и мои коллеги провели много часов, чтобы решить смешанный тип в классе, который я создал с помощью wsimport. Я пытаюсь настроить и настроить List<Object>, List<Serializable> или List<String>. Мы использовали простой wsimport, и мы не знали о нем:

<jaxb:globalBindings generateMixedExtensions="true"/>

Теперь я предлагаю вам создать простой пакет wsimport script, и это будет выпущено для клиента. Я думаю, вы можете использовать внешний файл привязки (-b параметр) в wsimport script.


Мартин Гребак написал замечательную статью по этой теме:

это хорошее решение избегать использования смешанного содержимого, особенно при разработке большой схемы с большим количеством расширений типа. Отображение такой схемы для любого обязательная структура обычно сложна и приводит к осложнениям и замедление развития. JAXB никогда не был разработан для случаев удобным способом - это структура отображения Java ↔ XML, и невозможно представить такой контент в иерархии объектов Java.

Я полностью согласился с Мартином. JAXB - простая инфраструктура отображения Java ↔ XML. Но в нем существует одна настройка, которая решает проблему с несколькими смешанными типами в одном XSD. Это generateMixedExtensions="true". Эта настройка изменяет поведение JAXB.


I'd really like to know why wsimport does this differently from xjc  

Я думаю, что вы изменяете поведение JAXB при использовании xjc и wsimport, используя простой JAXB без этой настройки.

Пожалуйста, проверьте wsimport 2.0 или wsimport 2.1 documetntation для параметры. Вот ссылка о модель смешанного контента, и если вы используете xs: любой в смешанном типе можете ли вы настроить его.