You are viewing a plain text version of this content. The canonical link for it is here.
Posted to java-dev@axis.apache.org by "Glanville, Jay Dickon (JIRA)" <ax...@ws.apache.org> on 2005/11/01 14:46:55 UTC

[jira] Created: (AXIS-2279) Doc/Wrapped service turns a non-null, empty array into a null object

Doc/Wrapped service turns a non-null, empty array into a null object
--------------------------------------------------------------------

         Key: AXIS-2279
         URL: http://issues.apache.org/jira/browse/AXIS-2279
     Project: Apache Axis
        Type: Bug
  Components: Serialization/Deserialization  
    Versions: 1.3    
    Reporter: Glanville, Jay Dickon


I have a service in which a non-null, empty array is returned:
   public XYZ[] getArray() throws AxisFault {
      return new XYZ[ 0 ];
   }
I then allow Axis to automatically generate the WSDL.  With this WSDL, I use the WSDL2Java tool to generate the client side libraries.

When my client calls the getArray() operation, it doesn't receive a non-null, empty array.  Instead, it receives a null object.

For example, if the client code was:
   XYZ[] ret = binding.getArray()
   if ( ret == null ) {
      System.out.println( "null" );
   } else {
      System.out.println( ret.length );
   }
then the output would be
   null

The client should be receiving what the service gave it.

The service is a document/literal-wrapped encoded service.  If I change the service to an RPC/encoded service, then everything works as expected (i.e.: the output of the client program would be "0").



-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators:
   http://issues.apache.org/jira/secure/Administrators.jspa
-
For more information on JIRA, see:
   http://www.atlassian.com/software/jira


[jira] Commented: (AXIS-2279) Doc/Wrapped service turns a non-null, empty array into a null object

Posted by "Maurizio Mlt (JIRA)" <ax...@ws.apache.org>.
    [ http://issues.apache.org/jira/browse/AXIS-2279?page=comments#action_12357132 ] 

Maurizio Mlt commented on AXIS-2279:
------------------------------------

This is due to the  WSDLs Axis generates when using RPC or Doc/Wrapped styles.

In the RPC case arrays are wrapped in XMLschema complexType while 
in the Doc/Wrapped case they are used  as simple repeated element  in the method response message declaration 

RPC)
 <wsdl:types> 
   ...
   <complexType name="ArrayOf_tns2_XYZ">
    <sequence>
     <element maxOccurs="unbounded" minOccurs="0" name="item" type="tns2:XYZ"/>
    </sequence>
   </complexType>
 </wsdl:types>
...
   <wsdl:message name="getArrayResponse">
      <wsdl:part name="getArrayReturn" type="impl:ArrayOf_tns2_XYZ"/>
   </wsdl:message>

Wrapped)
 <wsdl:types>
...
   <element name="getArrayResponse">
    <complexType>
     <sequence>
      <element maxOccurs="unbounded" name="getArrayReturn" type="tns2:XYZ"/>
     </sequence>
    </complexType>
   </element>
 </wsdl:types>
...
   <wsdl:message name="getArrayResponse">
      <wsdl:part element="impl:getArrayResponse" name="parameters"/>
   </wsdl:message>


*** Unzipping my comment

I've expaned a little bit more your example:

------ class MyWebService.java - XYZ..java
public class MyWebService{
   public XYZ[] getArray(){
           return new XYZ[0];
   }
}
public class XYZ {
   private String name;
   private int value;

   public XYZ(){
           name="";
           value=0;
   }
   public void setName(String name){  this.name=name;  }
   public void setValue(int value){ this.value=value;}
   public String getName(){ return name; }
   public int getValue(){ return value; }
}
------

I've then generated RPC/literal  WSDL:  java -cp $AXISCLASSPATH:. org.apache.axis.wsdl.Java2WSDL -o MyWebService.wsdl -l http://127.0.0.1:8080/MyWebService -n urn:MyWebService -pexample=urn:MyWebService -y RPC -u LITERAL MyWebService

------- MyWebService.wsdl.RPC-literal
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="urn:MyWebService" xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:impl="urn:MyWebService"
 xmlns:intf="urn:MyWebService" xmlns:tns2="http://DefaultNamespace" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdlsoap="ht
tp://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<!--WSDL created by Apache Axis version: 1.3
Built on Oct 05, 2005 (05:23:37 EDT)-->
 <wsdl:types>
  <schema targetNamespace="http://DefaultNamespace" xmlns="http://www.w3.org/2001/XMLSchema">
   <import namespace="urn:MyWebService"/>
   <import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
   <complexType name="XYZ">
    <sequence>
     <element name="name" nillable="true" type="xsd:string"/>
     <element name="value" type="xsd:int"/>
    </sequence>
   </complexType>
  </schema>
  <schema targetNamespace="urn:MyWebService" xmlns="http://www.w3.org/2001/XMLSchema">
   <import namespace="http://DefaultNamespace"/>
   <import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
   <complexType name="ArrayOf_tns2_XYZ">
    <sequence>
     <element maxOccurs="unbounded" minOccurs="0" name="item" type="tns2:XYZ"/>
    </sequence>
   </complexType>
  </schema>
 </wsdl:types>

   <wsdl:message name="getArrayRequest">
   </wsdl:message>
   <wsdl:message name="getArrayResponse">
      <wsdl:part name="getArrayReturn" type="impl:ArrayOf_tns2_XYZ"/>
   </wsdl:message>

   <wsdl:portType name="MyWebService">
      <wsdl:operation name="getArray">
         <wsdl:input message="impl:getArrayRequest" name="getArrayRequest"/>
         <wsdl:output message="impl:getArrayResponse" name="getArrayResponse"/>
      </wsdl:operation>
   </wsdl:portType>

   <wsdl:binding name="MyWebServiceSoapBinding" type="impl:MyWebService">
      <wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
      <wsdl:operation name="getArray">
         <wsdlsoap:operation soapAction=""/>
         <wsdl:input name="getArrayRequest">
            <wsdlsoap:body namespace="urn:MyWebService" use="literal"/>
         </wsdl:input>
         <wsdl:output name="getArrayResponse">
            <wsdlsoap:body namespace="urn:MyWebService" use="literal"/>
         </wsdl:output>
      </wsdl:operation>
   </wsdl:binding>
   <wsdl:service name="MyWebServiceService">
      <wsdl:port binding="impl:MyWebServiceSoapBinding" name="MyWebService">
         <wsdlsoap:address location="http://127.0.0.1:8080/MyWebService"/>
      </wsdl:port>
   </wsdl:service>

</wsdl:definitions>
-------

In this case note that Axis wraps the array of XYZ into an XML-schema complexType and use it as the return type of the getArray() method. 
   <wsdl:message name="getArrayResponse">
      <wsdl:part name="getArrayReturn" type="impl:ArrayOf_tns2_XYZ"/>
   </wsdl:message>

where ArrayOf_tns2_XYZ is 
   <complexType name="ArrayOf_tns2_XYZ">
    <sequence>
     <element maxOccurs="unbounded" minOccurs="0" name="item" type="tns2:XYZ"/>
    </sequence>
   </complexType>

In this case an array of  0 elements is correctly managed by Axis Serializer/Deserializer.


****** And there was evening, and there was morning...


I've then generated WRAPPED WSDL: 
java -cp $AXISCLASSPATH:. org.apache.axis.wsdl.Java2WSDL -o MyWebService.wsdl -l http://127.0.0.1:8080/MyWebService -n urn:MyWebService -pexample=urn:MyWebService -y WRAPPED MyWebService

------ MyWebService.wsdl.WRAPPED
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="urn:MyWebService" xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:impl="urn:MyWebService"
 xmlns:intf="urn:MyWebService" xmlns:tns2="http://DefaultNamespace" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdlsoap="ht
tp://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<!--WSDL created by Apache Axis version: 1.3
Built on Oct 05, 2005 (05:23:37 EDT)-->

 <wsdl:types>
  <schema elementFormDefault="qualified" targetNamespace="urn:MyWebService" xmlns="http://www.w3.org/2001/XMLSchema">
   <import namespace="http://DefaultNamespace"/>
   <element name="getArray">
    <complexType/>
   </element>
   <element name="getArrayResponse">
    <complexType>
     <sequence>
      <element maxOccurs="unbounded" name="getArrayReturn" type="tns2:XYZ"/>
     </sequence>
    </complexType>
   </element>
  </schema>
  <schema elementFormDefault="qualified" targetNamespace="http://DefaultNamespace" xmlns="http://www.w3.org/2001/XMLSchema">
   <complexType name="XYZ">
    <sequence>
     <element name="name" nillable="true" type="xsd:string"/>
     <element name="value" type="xsd:int"/>
    </sequence>
   </complexType>
  </schema>
 </wsdl:types>

   <wsdl:message name="getArrayRequest">
      <wsdl:part element="impl:getArray" name="parameters"/>
   </wsdl:message>
   <wsdl:message name="getArrayResponse">
      <wsdl:part element="impl:getArrayResponse" name="parameters"/>
   </wsdl:message>

   <wsdl:portType name="MyWebService">
      <wsdl:operation name="getArray">
         <wsdl:input message="impl:getArrayRequest" name="getArrayRequest"/>
         <wsdl:output message="impl:getArrayResponse" name="getArrayResponse"/>
      </wsdl:operation>
   </wsdl:portType>

   <wsdl:binding name="MyWebServiceSoapBinding" type="impl:MyWebService">
      <wsdlsoap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
      <wsdl:operation name="getArray">
         <wsdlsoap:operation soapAction=""/>
         <wsdl:input name="getArrayRequest">
            <wsdlsoap:body use="literal"/>
         </wsdl:input>
         <wsdl:output name="getArrayResponse">
            <wsdlsoap:body use="literal"/>
         </wsdl:output>
      </wsdl:operation>
   </wsdl:binding>

   <wsdl:service name="MyWebServiceService">
      <wsdl:port binding="impl:MyWebServiceSoapBinding" name="MyWebService">
         <wsdlsoap:address location="http://127.0.0.1:8080/MyWebService"/>
      </wsdl:port>
   </wsdl:service>
</wsdl:definitions>
-------

As you can see in this case it doesn't wrap the Array in a complexType as in the RPC literal case (as I'd expect...) but it 
leaves it as a repeated element in the getArray response element:
   <element name="getArrayResponse">
    <complexType>
     <sequence>
      <element maxOccurs="unbounded" name="getArrayReturn" type="tns2:XYZ"/>
     </sequence>
    </complexType>
   </element>

In this case you get a NullPointerException if a 0 elements array is sent.

Note that this happens also if you modify  line <element maxOccurs="unbounded" name="getArrayReturn" type="tns2:XYZ"/> as <element maxOccurs="unbounded" minOccurs="0" name="getArrayReturn" type="tns2:XYZ"/>.


*** My solution 
What I did in order to obtain a WRAPPED WSDL/SOAP solution working as I would expect  was to manually edit  the (WRAPPED) WSDL file wrapping the array in a complexType:
   <element name="getArrayResponse">
    <complexType>
     <sequence>
      <element name="getArrayReturn" type="tns2:ArrayOfXYZ"/>
     </sequence>
    </complexType>
   </element>
...
   <complexType name="ArrayOfXYZ">
    <sequence>
     <element maxOccurs="unbounded" minOccurs="0" name="item" type="tns2:XYZ"/>
    </sequence>
   </complexType>

-
*** Concluding...

The same problem and solution would apply also to arrays passed  as arguments of methods.


Is it a bug ? 
Is it an error to assume Axis should wrap arrays when used as return/argument  types  in  methods?
Is there a way to force Axis to wrap arrays anyway?
  
Personally I choose to work in RPC/literal mode in order to avoid the burden of  manually editing the WSDL doc 
for fufure evolution and re-generations...



> Doc/Wrapped service turns a non-null, empty array into a null object
> --------------------------------------------------------------------
>
>          Key: AXIS-2279
>          URL: http://issues.apache.org/jira/browse/AXIS-2279
>      Project: Apache Axis
>         Type: Bug
>   Components: Serialization/Deserialization
>     Versions: 1.3
>     Reporter: Glanville, Jay Dickon

>
> I have a service in which a non-null, empty array is returned:
>    public XYZ[] getArray() throws AxisFault {
>       return new XYZ[ 0 ];
>    }
> I then allow Axis to automatically generate the WSDL.  With this WSDL, I use the WSDL2Java tool to generate the client side libraries.
> When my client calls the getArray() operation, it doesn't receive a non-null, empty array.  Instead, it receives a null object.
> For example, if the client code was:
>    XYZ[] ret = binding.getArray()
>    if ( ret == null ) {
>       System.out.println( "null" );
>    } else {
>       System.out.println( ret.length );
>    }
> then the output would be
>    null
> The client should be receiving what the service gave it.
> The service is a document/literal-wrapped encoded service.  If I change the service to an RPC/encoded service, then everything works as expected (i.e.: the output of the client program would be "0").

-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators:
   http://issues.apache.org/jira/secure/Administrators.jspa
-
For more information on JIRA, see:
   http://www.atlassian.com/software/jira