Mixed Content for JAXB not working from WSDL
Asked Answered
I

2

15

I'm using NetBeans and I have two projects:

  • A EJB Module to generate a webservice and deploy it to GlassFish
  • A simple console client to test and consume this webservice

For the webservice, I'm using an XSD with mixed content elements. Adding a binding file for JAXB import with the following code worked:

<?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>

It generated this code:

@XmlMixed
@OverrideAnnotationOf
protected List<Serializable> contentOverrideForED;

I can live with this generated code, although it's not ideal.

My problem is with the client, for which I've added a Web Service Reference to my generated and deployed webservice, running simply on localhost.

Using the same binding file in WSDL Customization: External Binding File doesn't yield the content code, nor does using it directly as an option for Wsimport, nor using it as a Jaxb option. I have a feeling that this setting is being disregarded somehow, but how?

And why does the initial JAXB generation include it and why doesn't wsimport use it? I'm kind of puzzled here.

Ischia answered 29/11, 2013 at 15:19 Comment(1)
Are you setting the packagename parameter to wsimport? Remove -p parameter from the wsimport command line, if you set it will be override the binding files.Excogitate
D
4

Great question! I and my collegaues spent many hours to solve mixed type in class which I generated with wsimport. I try many adjust and get List<Object>, List<Serializable> or List<String>. We used simple wsimport and we didn't know about:

<jaxb:globalBindings generateMixedExtensions="true"/>

Now, I offer you to create simple wsimport batch script and this released for customer. I think you can use external binding file (-b parameter) in wsimport script.


Martin Grebac wrote great article about this topic:

it is a good decision to avoid use of mixed content, especially when designing a large schema with a lot of type extensions. Mapping that kind of schema to any binding framework is usually complex and leads to complications and slowdown of development. JAXB has never been designed to handle these cases in a convenient way - it is a Java <-> XML mapping framework, and it's not possible to represent this kind of content in a hierarchy of Java objects.

I fully agreed with a Martin. The JAXB is simple Java <-> XML mapping framework. But It is existing one customization which solved problem with multiple mixed type in one XSD. That is generateMixedExtensions="true". This customization is change the behaviour of JAXB.


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

I think you are change behavior of JAXB when use xjc and wsimport use simple JAXB without this customization.

Please check wsimport 2.0 or wsimport 2.1 documetntation for parameters. Here is link about mixed content model and if you use xs:any in mixed type can you adjust it.

Dannadannel answered 10/12, 2013 at 8:4 Comment(0)
T
2

You may want to consider using Eclipse to gen what you need. Even though the xsd and wsdl you are using isn't included in the question, I came up with a simple example that seems to work. I did not use a bindings file, the wizard in Eclipse picked the fact that mixed was needed because mixed="true" in the XSD (may want to try yours with no binding):

<?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>

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

    }

Implementation:

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

    }

Class "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;
        }

    }
Thrasonical answered 10/12, 2013 at 1:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.