Have you tried using the built-in HashMap type provided by apachesoap:

Types definition:
<schema targetNamespace="http://xml.apache.org/xml-soap";
xmlns="http://www.w3.org/2001/XMLSchema";>
  <import namespace="http://schemas.xmlsoap.org/soap/encoding/"; /> 
  <complexType name="mapItem">
   <sequence>
    <element name="key" nillable="true" type="xsd:string" /> 
    <element name="value" nillable="true" type="xsd:string" /> 
   </sequence>
  </complexType>
  <complexType name="Map">
   <sequence>
    <element maxOccurs="unbounded" minOccurs="0" name="item"
type="apachesoap:mapItem" /> 
   </sequence>
  </complexType>
</schema>

Message definition:
<wsdl:message name="authorizeToAuctionResponse">
  <wsdl:part name="authorizeToAuctionReturn" type="apachesoap:Map" /> 
</wsdl:message>

Works like a charm from SOAP::Lite!

-----Original Message-----
From: Scott Ellsworth [mailto:[EMAIL PROTECTED] 
Sent: Friday, December 12, 2003 2:55 PM
To: [EMAIL PROTECTED]
Subject: Proper WSDL allowing Axis to interpret a SOAP::Lite hash ref


Hi, all.

I have searched the archives, but have not gotten quite enough of a  
clue to solve the problem I face.  I wish to use Java to get the  
results from a call to a SOAP server running Perl SOAP::Lite.  The  
function returns a hash ref, encoded as SOAP::Lite encodes.  (raw soap  
call/return below.)

I apologize for the long message, but I have found that God is in the  
details in this space, and if it is just a simple typo in some routine,  
the real source is required.

The server is running SOAP::Lite 0.55.  It is sending back a hashref,  
and I have not been able to create the proper WSDL to see it, possibly  
because of how SOAP::Lite is sending back that hashref.  I can handle  
simple types like ints and strings, but this is not working.

I am using stubs created by wsdl2java, so clearly I need to express  
this soap-struct in my WSDL, but I do not seem to be able to create the  
proper type in the WSDL, or at least, it is not being used.

I cannot really change the underlying routines on the server, as they  
are used for many things, but I can modify the dispatch function called  
by mod_perl.  I have attached it at the end.

The request:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!--
   URL: http://feature.alodar.com/gbib-soap/
   -->
<soap:Envelope
           xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/";
           soap:encodingstyle="http://schemas.xmlsoap.org/soap/encoding/";
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
           xmlns:xsd="http://www.w3.org/2001/XMLSchema";>
   <soap:Body>
     <s0:get_user_ids_by_name  
xmlns:s0="http://feature.alodar.com/Alodar/GBIB/UserUtils";>
       <s0:arg1Name>config_name</s0:arg1Name>
       <s0:arg1Value>feature</s0:arg1Value>
     </s0:get_user_ids_by_name>
   </soap:Body>
</soap:Envelope>

The response:

<?xml version="1.0" encoding="UTF-8"?>
<soap-env:envelope  
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance";  
xmlns:soap-enc="http://schemas.xmlsoap.org/soap/encoding/";  
xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/";  
xmlns:xsd="http://www.w3.org/1999/XMLSchema";  
xmlns:namesp2="http://xml.apache.org/xml-soap";  
soap-env:encodingstyle="http://schemas.xmlsoap.org/soap/encoding/";>
        <soap-env:body>
                <namesp1:get_user_ids_by_nameresponse  
xmlns:namesp1="http://feature.alodar.com/Alodar/GBIB/UserUtils";>
                        <s-gensym3 xsi:type="namesp2:SOAPStruct">
                                <admin xsi:type="xsd:int">
                                        1
                                </admin>
                                <guest xsi:type="xsd:int">
                                        2
                                </guest>
                        </s-gensym3>
                </namesp1:get_user_ids_by_nameresponse>
        </soap-env:body>
</soap-env:envelope>

my WSDL:

<?xml version="1.0" encoding="utf-8"?>
<definitions name="GBIB"
   targetNamespace="http://feature.alodar.com/Alodar/GBIB/";
   xmlns:schema="http://www.w3.org/2001/XMLSchema";
   xmlns:tns="http://feature.alodar.com/Alodar/GBIB/";
   xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/";
   xmlns:xml-soap="http://xml.apache.org/xml-soap";
   xmlns="http://schemas.xmlsoap.org/wsdl/";
   >

    <types>
       <!-- I could use the following by defining the type returned from  
a
            part of a message as
            <message name="ListOfUsers">
              <part name="models" type="tns:Vector">
            </message>
       <xsd:schema
          targetNamespace="http://feature.alodar.com/Alodar/GBIB/";
          xmlns="http://www.w3.org/2001/XMLSchema/";>
          <schema:complexType name="Vector">
             <xsd:element name="elementData" type="schema:String" />
             <xsd:element name="elementCount" type="schema:int" />
          </schema:complexType>
       </xsd:schema>
       -->
       <schema
          xmlns="http://www.w3.org/2001/XMLSchema";
          targetNamespace="http://feature.alodar.com/Alodar/GBIB/";
       >
          <complexType name="idNameMap">
             <element name="elementData" type="string" />
             <element name="elementCount" type="int" />
          </complexType>
          <complexType name="SOAPStruct">
            <all>
              <element name="varString" type="string"/>
              <element name="varInt" type="int"/>
            </all>
          </complexType>
       </schema>
   </types>

        <message name="config_nameRequest">
                <part name="arg1Name" type="schema:string" />
                <part name="arg1Value" type="schema:string" />
        </message>
        <message name="stringStringRequest">
                <part name="arg1Name" type="schema:string" />
                <part name="arg1Value" type="schema:string" />
                <part name="arg2Name" type="schema:string" />
                <part name="arg2Value" type="schema:string" />
        </message>
        <message name="stringIntRequest">
                <part name="arg1Name" type="schema:string" />
                <part name="arg1Value" type="schema:string" />
                <part name="arg2Name" type="schema:string" />
                <part name="arg2Value" type="schema:int" />
        </message>
        <message name="idNameMapResponse">
                <!-- part name="idNameMapReturnValue" type="xml-soap:Map" /
-->
                <part name="idNameMapReturnValue" type="tns:idNameMap" />
        </message>
        <message name="stringResponse">
                <part name="stringReturnValue" type="schema:string" />
        </message>
        <message name="intResponse">
                <part name="stringReturnValue" type="schema:int" />
        </message>
        <message name="get_public_listsResponse">
                <part name="get_public_listsReturnValue"
type="schema:anyType" />
        </message>
        
        <portType name="UserUtilsPort">
                <!-- ports are analogous to method calls.  SR says analogous
to  
library/module/class -->
                <!-- name must match some binding's type -->
                <operation name="get_user_ids_by_name">
                        <input message="tns:config_nameRequest" />
                        <output message="tns:idNameMapResponse" />
                </operation>
                <operation name="get_id_for_username">
                        <input message="tns:stringStringRequest" />
                        <output message="tns:intResponse" />
                </operation>
                <operation name="get_username_for_id">
                        <input message="tns:stringIntRequest" />
                        <output message="tns:stringResponse" />
                </operation>
        </portType>
        
        <portType name="ListUtilsPort">
                <!-- ports are analogous to method calls. -->
                <!-- name must match some binding's type -->
                <operation name="get_public_lists">
                        <input message="tns:config_nameRequest" />
                        <output message="tns:stringResponse" />
                </operation>
        </portType>
        
        <binding name="UserUtils" type="tns:UserUtilsPort">
                <!-- binding elements tell code how to move data.  We are
using SOAP  
-->
                <!-- These are analagous to classes -->
                <!-- type matches name of some port -->
                <soap:binding style="rpc"  
transport="http://schemas.xmlsoap.org/soap/http"; />
                <operation name="get_id_for_username">
                        <soap:operation style="rpc" />
                        <input>
                                <soap:body use="encoded"  
namespace="http://feature.alodar.com/Alodar/GBIB/UserUtils";  
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"; />
                        </input>
                        <output>
                                <soap:body use="encoded"  
namespace="http://feature.alodar.com/Alodar/GBIB/UserUtils";  
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"; />
                        </output>
                </operation>
                <operation name="get_user_ids_by_name">
                        <soap:operation style="rpc" />
                        <input>
                                <soap:body use="encoded"  
namespace="http://feature.alodar.com/Alodar/GBIB/UserUtils";  
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"; />
                        </input>
                        <output>
                                <soap:body use="encoded"  
namespace="http://feature.alodar.com/Alodar/GBIB/UserUtils";  
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"; />
                        </output>
                </operation>
                <operation name="get_username_for_id">
                        <soap:operation style="rpc" />
                        <input>
                                <soap:body use="encoded"  
namespace="http://feature.alodar.com/Alodar/GBIB/UserUtils";  
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"; />
                        </input>
                        <output>
                                <soap:body use="encoded"  
namespace="http://feature.alodar.com/Alodar/GBIB/UserUtils";  
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"; />
                        </output>
                </operation>
        </binding>

        <binding name="ListUtils" type="tns:ListUtilsPort">
                <!-- binding elements tell code how to move data.  We are
using SOAP  
-->
                <!-- These are analagous to classes -->
                <!-- type matches name of some port -->
                <soap:binding style="rpc"  
transport="http://schemas.xmlsoap.org/soap/http"; />
                <operation name="get_public_lists">
                        <soap:operation style="rpc" />
                        <input>
                                <soap:body use="encoded"  
namespace="http://feature.alodar.com/Alodar/GBIB/ListUtils";  
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"; />
                        </input>
                        <output>
                                <soap:body use="encoded"  
namespace="http://feature.alodar.com/Alodar/GBIB/ListUtils";  
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"; />
                        </output>
                </operation>
        </binding>

        <service name="GBIBService">
                <!-- service tells us what bindings to use.  These give
actual  
machines that implement the protocol. -->
                <!-- document>
                        For a complete description of this service, go to
the following URL:
                        <a href="http://feature.alodar.com/";>
                                http://feature.alodar.com/
                        </a>
                </document -->
                <port name="UserUtils" binding="tns:UserUtils">
                        <soap:address
location="http://feature.alodar.com/gbib-soap"; />
                </port>
                <port name="ListUtils" binding="tns:ListUtils">
                        <soap:address
location="http://feature.alodar.com/gbib-soap"; />
                </port>
        </service>
</definitions>

The java code:

    public void callFeatureStub() {
                try{
                        String endpoint =
"http://feature.alodar.com/gbib-soap/";;

           UserUtilsPort userUtilsPort = new  
GBIBServiceLocator().getUserUtils(new URL(endpoint));
           ((UserUtilsStub)userUtilsPort).setTimeout(60000);
           ListUtilsPort listUtilsPort = new  
GBIBServiceLocator().getListUtils(new URL(endpoint));
           ((ListUtilsStub)listUtilsPort).setTimeout(60000);

// works great!

            int  
get_id_for_usernameResult=userUtilsPort.get_id_for_username("config_name 
", config_name, "username", "admin");
                        printResult("get_id_for_username",
get_id_for_usernameResult);

//works great!

            String  
get_username_for_idResult=userUtilsPort.get_username_for_id("config_name 
", config_name, "user_id", 1);
                        printResult("get_username_for_id",
get_username_for_idResult);

// throws exception
                        Object get_user_ids_by_nameResult =  
userUtilsPort.get_user_ids_by_name("config_name", config_name);
                        printResult("get_user_ids_by_name",
get_user_ids_by_nameResult);

        } catch (Exception e) {
            System.err.println("Error: "+e.toString());
        }
    }

The dispatcher is very simple:

sub handler {
   SOAP::Transport::HTTP::Apache -> dispatch_to(
       qw(
           Alodar::GBIB::ListUtils::get_public_lists
           Alodar::GBIB::UserUtils::get_id_for_username
           Alodar::GBIB::UserUtils::get_user_ids_by_name
           Alodar::GBIB::UserUtils::get_username_for_id
       )
   ) ->handler(@_)

I can add more things to this, as long as they can go here.

The exception is:

      [java] Result of get_id_for_username was type int, value 1
      [java] Result of get_username_for_id was type java.lang.String,  
value admin
      [java] - Exception:
      [java] org.xml.sax.SAXException: Deserializing parameter  
's-gensym39':  could not find deserializer for type  
{http://xml.apache.org/xml-soap}SOAPStruct
      [java]     at  
org.apache.axis.message.RPCHandler.onStartChild(RPCHandler.java:302)
      [java] Error: org.xml.sax.SAXException: Deserializing parameter  
's-gensym39':  could not find deserializer for type  
{http://xml.apache.org/xml-soap}SOAPStruct
      [java]     at  
org.apache.axis.encoding.DeserializationContextImpl.startElement(Deseria 
lizationContextImpl.java:963)
      [java]     at  
org.apache.axis.message.SAX2EventRecorder.replay(SAX2EventRecorder.java: 
198)
      [java]     at  
org.apache.axis.message.MessageElement.publishToHandler(MessageElement.j 
ava:722)
      [java]     at  
org.apache.axis.message.RPCElement.deserialize(RPCElement.java:233)
      [java]     at  
org.apache.axis.message.RPCElement.getParams(RPCElement.java:347)
      [java]     at org.apache.axis.client.Call.invoke(Call.java:2272)
      [java]     at org.apache.axis.client.Call.invoke(Call.java:2171)
      [java]     at org.apache.axis.client.Call.invoke(Call.java:1691)
      [java]     at  
com.alodar.feature.Alodar.GBIB.UserUtilsStub.get_user_ids_by_name(UserUt 
ilsStub.java:187)
      [java]     at axisTest.callFeatureStub(axisTest.java:71)
      [java]     at axisTest.main(axisTest.java:46)

Scott

Reply via email to