9 Replies Latest reply on Aug 9, 2005 4:57 AM by Thomas Diesler

    Handling array types by JBossWS Tools

    Anil Saldanha Master

      wscompile handles arrays in a special way. It isolates the array types even when the base type is a Java wrapper types like Integer into a different namespace and then imports them into the target namespace, as shown below.


      package org.jboss.test.ws.tools.sei;
      
      import org.jboss.test.ws.jaxb.sei.Base;
      
      import java.rmi.Remote;
      import java.rmi.RemoteException;
      
      /**
       * An SEI with an array type
       *
       * @author <mailto:Anil.Saldhana@jboss.org>Anil Saldhana
       * @since Nov 3, 2004
       */
      public interface ArrayInterface extends Remote
      {
       public void customMethod(Base base, Integer[] a) throws RemoteException, SomeException;
      }
      



      The wsdl that is generated is:
      <?xml version="1.0" encoding="UTF-8"?>
      
      <definitions name="ArrayInterfaceService" targetNamespace="http://org.jboss.ws" xmlns:tns="http://org.jboss.ws" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:ns2="http://arrays/java/lang">
       <types>
       <schema targetNamespace="http://arrays/java/lang" xmlns:tns="http://arrays/java/lang" xmlns:soap11-enc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://www.w3.org/2001/XMLSchema">
       <import namespace="http://org.jboss.ws"/>
       <complexType name="IntegerArray">
       <sequence>
       <element name="value" type="int" nillable="true" minOccurs="0" maxOccurs="unbounded"/></sequence></complexType></schema>
       <schema targetNamespace="http://org.jboss.ws" xmlns:tns="http://org.jboss.ws" xmlns:soap11-enc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://www.w3.org/2001/XMLSchema">
       <import namespace="http://arrays/java/lang"/>
       <complexType name="Base">
       <sequence>
       <element name="a" type="int"/>
       <element name="b" type="int"/></sequence></complexType>
       <complexType name="SomeException">
       <sequence/></complexType>
       <element name="SomeException" type="tns:SomeException"/></schema></types>
       <message name="ArrayInterface_customMethod">
       <part name="Base_1" type="tns:Base"/>
       <part name="arrayOfInteger_2" type="ns2:IntegerArray"/></message>
       <message name="ArrayInterface_customMethodResponse"/>
       <message name="SomeException">
       <part name="SomeException" element="tns:SomeException"/></message>
       <portType name="ArrayInterface">
       <operation name="customMethod" parameterOrder="Base_1 arrayOfInteger_2">
       <input message="tns:ArrayInterface_customMethod"/>
       <output message="tns:ArrayInterface_customMethodResponse"/>
       <fault name="SomeException" message="tns:SomeException"/></operation></portType>
       <binding name="ArrayInterfaceBinding" type="tns:ArrayInterface">
       <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc"/>
       <operation name="customMethod">
       <soap:operation soapAction=""/>
       <input>
       <soap:body use="literal" namespace="http://org.jboss.ws"/></input>
       <output>
       <soap:body use="literal" namespace="http://org.jboss.ws"/></output>
       <fault name="SomeException">
       <soap:fault name="SomeException" use="literal"/></fault></operation></binding>
       <service name="ArrayInterfaceService">
       <port name="ArrayInterfacePort" binding="tns:ArrayInterfaceBinding">
       <soap:address location="REPLACE_WITH_ACTUAL_URL"/></port></service></definitions>
      


      As you can see, wscompile has special array handling.

      When there are custom user types and arrays of them, it is similar.
      /*
       * JBoss, the OpenSource J2EE webOS
       *
       * Distributable under LGPL license.
       * See terms of license at gnu.org.
       */
      
      package org.jboss.test.ws.tools.jbws_161.custom;
      
      /**
       * Remote interface for Hello.
       */
      public interface HelloCustomRemote
       extends java.rmi.Remote
      {
      
       public String helloString(String name)
       throws java.rmi.RemoteException;
      
       public HelloObj helloBean(HelloObj bean)
       throws java.rmi.RemoteException;
      
       public HelloObj[] helloArray(HelloObj[] query)
       throws java.rmi.RemoteException;
      
      }
      
      


      <?xml version="1.0" encoding="UTF-8"?>
      
      <definitions name="HelloCustomService"
       targetNamespace="http://org.jboss/types"
       xmlns:tns="http://org.jboss/types"
       xmlns="http://schemas.xmlsoap.org/wsdl/"
       xmlns:ns2="http://org.jboss/types/arrays/org/jboss/test/ws/tools/jbws_161/custom"
       xmlns:xsd="http://www.w3.org/2001/XMLSchema"
       xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
       <types>
       <schema targetNamespace="http://org.jboss/types/arrays/org/jboss/test/ws/tools/jbws_161/custom"
       xmlns:tns="http://org.jboss/types/arrays/org/jboss/test/ws/tools/jbws_161/custom"
       xmlns:soap11-enc="http://schemas.xmlsoap.org/soap/encoding/"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:ns2="http://org.jboss/types"
       xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
       xmlns="http://www.w3.org/2001/XMLSchema">
       <import namespace="http://org.jboss/types"/>
       <complexType name="HelloObjArray">
       <sequence>
       <element name="value" type="ns2:HelloObj" nillable="true" minOccurs="0" maxOccurs="unbounded"/>
       </sequence>
       </complexType>
       </schema>
       <schema targetNamespace="http://org.jboss/types"
       xmlns:tns="http://org.jboss/types"
       xmlns:soap11-enc="http://schemas.xmlsoap.org/soap/encoding/"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
       xmlns="http://www.w3.org/2001/XMLSchema">
      
       <import namespace="http://org.jboss/types/arrays/org/jboss/test/ws/tools/jbws_161/custom"/>
       <complexType name="HelloObj">
       <sequence>
       <element name="msg" type="string" nillable="true"/>
       </sequence>
       </complexType>
       </schema>
       </types>
       <message name="HelloCustomRemote_helloArray">
       <part name="arrayOfHelloObj_1" type="ns2:HelloObjArray"/>
       </message>
       <message name="HelloCustomRemote_helloArrayResponse">
       <part name="result" type="ns2:HelloObjArray"/>
       </message>
       <message name="HelloCustomRemote_helloBean">
       <part name="HelloObj_1" type="tns:HelloObj"/>
       </message>
       <message name="HelloCustomRemote_helloBeanResponse">
       <part name="result" type="tns:HelloObj"/>
       </message>
       <message name="HelloCustomRemote_helloString">
       <part name="String_1" type="xsd:string"/>
       </message>
       <message name="HelloCustomRemote_helloStringResponse">
       <part name="result" type="xsd:string"/>
       </message>
       <portType name="HelloCustomRemote">
       <operation name="helloArray" parameterOrder="arrayOfHelloObj_1">
       <input message="tns:HelloCustomRemote_helloArray"/>
       <output message="tns:HelloCustomRemote_helloArrayResponse"/>
       </operation>
       <operation name="helloBean" parameterOrder="HelloObj_1">
       <input message="tns:HelloCustomRemote_helloBean"/>
       <output message="tns:HelloCustomRemote_helloBeanResponse"/>
       </operation>
       <operation name="helloString" parameterOrder="String_1">
       <input message="tns:HelloCustomRemote_helloString"/>
       <output message="tns:HelloCustomRemote_helloStringResponse"/>
       </operation>
       </portType>
       <binding name="HelloCustomRemoteBinding" type="tns:HelloCustomRemote">
       <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc"/>
       <operation name="helloArray">
       <soap:operation soapAction=""/>
       <input>
       <soap:body use="literal" namespace="http://org.jboss/types"/>
       </input>
       <output>
       <soap:body use="literal" namespace="http://org.jboss/types"/>
       </output>
       </operation>
       <operation name="helloBean">
       <soap:operation soapAction=""/>
       <input>
       <soap:body use="literal" namespace="http://org.jboss/types"/>
       </input>
       <output>
       <soap:body use="literal" namespace="http://org.jboss/types"/>
       </output>
       </operation>
       <operation name="helloString">
       <soap:operation soapAction=""/>
       <input>
       <soap:body use="literal" namespace="http://org.jboss/types"/>
       </input>
       <output>
       <soap:body use="literal" namespace="http://org.jboss/types"/>
       </output>
       </operation>
       </binding>
       <service name="HelloCustomService">
       <port name="HelloCustomRemotePort" binding="tns:HelloCustomRemoteBinding">
       <soap:address location="REPLACE_WITH_ACTUAL_URL"/>
       </port>
       </service>
      </definitions>
      



      So this is a task that needs to be implemented with care and solid testcases.

        • 2. Re: Handling array types by JBossWS Tools
          Anil Saldanha Master

          Handling array types the way wscompile does has complicated the tools code to the extent that I fear I will have difficulty maintaining it for the vast gamut of requirements for J2EE 5.

          One reason I am apprehensive about the approach is that there is no intuitive order in which wscompile generates the namespaces ns2,ns3 etc. An example is the StandardTypes SEI in the testsuite and the wsdl that is generated by wscompile - "MarshallService.wsdl". Tell me if you can figure out how wscompile generates the namespaces ns2,ns3 etc.

          • 3. Re: Handling array types by JBossWS Tools
            Thomas Diesler Master

            The prefix assocciation (ns1, ns2, ...) with a namespace uri is not relevant for two schemas to be semantically equivalent.

            It is probable that wscompile puts array types in seperate schema files to associate them with different target namespaces and such avoids name collisions. Is is all about reuse of the defined type in a different schema.

            Image you have two comlex java types that live in two different packages and both use the same array type. For that scenario it makes sense to define the array type in yet another schema.

            Whether jbossws tools produces output that is equivalent to wscompile largely depends on the validation algorithm. Lexical equivalencs is not required neither the use of identical namespace prefixes.


            When schema components are imported from multiple namespaces, each namespace
            must be identified with a separate import element. The import elements themselves
            must appear as the first children of the schema element. Furthermore, each namespace
            must be associated with a prefix, using a standard namespace declaration, and that
            prefix is used to qualify references to any schema components belonging to that
            namespace. Finally, import elements optionally contain a schemaLocation attribute to
            help locate resources associated with the namespaces.


            • 4. Re: Handling array types by JBossWS Tools
              Alexey Loubyansky Master

              AFAICS in our testsuite, when I see a type in an XSD defined following this 'array' template, it's not necessarily bound to an array in Java.

              For example.

              testsuite/src/resources/webservice/marshalltest-doclit/META-INF/wsdl/MarshallDocLitService.wsdl

               <complexType name="LongArr">
               <sequence>
               <element name="longArr" type="long" minOccurs="0" maxOccurs="unbounded"/>
               </sequence>
               </complexType>
              


              Isn't this TYPE bound to a class that wrapps the array?

              package org.jboss.test.webservice.marshalltest.types;
              
              public class LongArr
              {
               private long[] longArr;
              
               public LongArr()
               {
               }
              
               public LongArr(long[] longArr)
               {
               this.longArr = longArr;
               }
              ...
              


              • 5. Re: Handling array types by JBossWS Tools
                Jason Greene Master

                Actually, that example also uses a wrapper element.

                <complexType name="echoLongArray">
                 <sequence>
                 <element name="LongArr_1" type="tns:LongArr" nillable="true"/>
                 </sequence>
                </complexType>


                So the correct serialization would be:
                <LongArr_1>
                 <longArr>1</longArr>
                 <longArr>2</longArr>
                 <longArr>3</longArr>
                </LongArr_1>


                According to the JAXB spec, this is one of the 2 ways an array in Java can be represented in schema. The other is the way you mention. Also, according to the spec, the element wrapping style is not the default. In order, to use this style you are supposed to mark the field with an @XmlElementWrapper annotation. (See https://jaxb.dev.java.net/nonav/jaxb20-pr/api/javax/xml/bind/annotation/XmlElementWrapper.html)

                Contrary to the JAXB methodology, WS-I Basic Profile 1.1 demonstrates serialization using element wrappers. I will have to research this further. So far I have not seen any mention in the public review of JAX-WS 2.0 as to how this is configured with the stack. I may need to take a look at the Sun EA release.

                -Jason


                • 6. Re: Handling array types by JBossWS Tools
                  Thomas Diesler Master

                  Yes, there maybe a bean that wraps the array. However we cannot force the public API to always use these wrapper types.

                  A good example is a DII client that uses an array as operation parameter. In that case there will be no wrapper bean.

                  • 7. Re: Handling array types by JBossWS Tools
                    Alexey Loubyansky Master

                    If there are two ways to bind arrays, there must be one which is the default one. The other one should be specified with binding customizations, e.g. jaxrpc-mapping.
                    Can we agree on this? Let's create a testcase that would demonstrate this.

                    • 8. Re: Handling array types by JBossWS Tools
                      Jason Greene Master

                       


                      If there are two ways to bind arrays, there must be one which is the default one.


                      JAXB2.0 spec says the default is non-wrapped for collections (includes arrays). Also it appears that JAXB can identify the wrapped style (when generating java classes from schema) by naming convention. The spec says the wrapper element should be named the same as the nested elements, and that name should match the property name.

                      I checked the jaxws ea, and it looks like they follow the jaxb specs defaults. Here is a document wrapped service taking 2 arrays:

                      <xs:complexType name="echoInts">
                       <xs:sequence>
                       <xs:element name="arg0" type="xs:int" form="qualified" maxOccurs="unbounded" minOccurs="0"/>
                       <xs:element name="arg1" type="xs:string" form="qualified" maxOccurs="unbounded" minOccurs="0"/>
                       </xs:sequence>
                       </xs:complexType>
                      


                      This is pretty much a contradiction of JAXRPC-1.1 which specifies there must be a wrapping element.

                      -Jason




                      • 9. Re: Handling array types by JBossWS Tools
                        Thomas Diesler Master

                        This argument is IMO only relevant to wstools. The marshalling layer has a contract with the WS layer to generate/consume XML fragments that conform to the given schema + mapping information.

                        I see two cases:

                        1) The complex type that denotes the array is mapped (in jaxrpc-mapping) to an array of java objects or primitives

                        2) The complex type that denotes the array is mapped to a wrapper bean

                        Case (2) is no different to marshalling/unmarshalling any other bean

                        Case (1) needs to be supported and is covered by the marshall.rpclit test cases