Thanks a lot, Scott.  The PropertyBagSerializer works like a charm.

However, it helps reveal a minor headache(about the null/nil problem).
Here is the detail:

  In the xml envolope, there is one element:  
     <smiles xsi:nil="true"/>
  which replects the hash on the perl side has an undefined value for
the "smiles" key.

  And the Apache-Soap client firmly complains:

     Exception in thread "main" java.lang.IllegalArgumentException: No
mapping found for ':smiles' using 
     encoding style 'http://schemas.xmlsoap.org/soap/encoding/'.

Since the WS server is in Perl(with SOAP::Lite), it seems like there is
no way for me to control the deployment xml
As I could if the WS server were in Java(with Apache-Soap-2.3.1).

In this situation, I wonder if there is a way to tweak the client to let
it deseralize the <smiles xsi:nil="true"/>
To a null.   Otherwise, I have to make the WS server to serve an empty
string for every undefined value, which leaves
The burden to the client.

Donald

-----Original Message-----
From: Scott Nichol [mailto:[EMAIL PROTECTED] 
Sent: Friday, August 06, 2004 8:18 PM
To: [EMAIL PROTECTED]
Subject: Re: How to deseralize a hashtable?


Subsequent to the 2.3.1 release, I wrote a PropertyBagSerializer
(http://cvs.apache.org/viewcvs.cgi/*checkout*/ws-soap/java/src/org/apach
e/soap/encoding/soapenc/PropertyBagSerializer.java?rev=1.3) that can be
used for this.  You would need to either get the last nightly build and
use it instead of 2.3.1, or just grab the code from the CVS link above,
compile it, and put the byte code in your classpath.  Your client code
would look like

        SOAPMappingRegistry smrr = new SOAPMappingRegistry ();
        PropertyBagSerializer pbs = new PropertyBagSerializer ();
        smrr.mapTypes(Constants.NS_URI_SOAP_ENC, new
QName("http://xml.apache.org/xml-soap";, "SOAPStruct"), Hashtable.class,
null, pbs);

Scott Nichol

Do not send e-mail directly to this e-mail address,
because it is filtered to accept only mail from
specific mail lists.
----- Original Message ----- 
From: "Chen, Donald" <[EMAIL PROTECTED]>
To: <[EMAIL PROTECTED]>
Sent: Friday, August 06, 2004 5:08 PM
Subject: How to deseralize a hashtable?


Hi, All.

I have a WS in Perl via SOAP::Lite.  Via this WS, a client can call a
method getAllInfo() which returns a Hashtable.  I wrote a WS client in
perl with success, but writing a WS client in Java via the
Apache-Soap-2.3.1 is never successful.

Specifically, the error I got is like this:

Exception in thread "main" java.lang.IllegalArgumentException: No
Deserializer found to deserialize a
'http://xml.apache.org/xml-soap:SOAPStruct' using encoding style
'http://schemas.xmlsoap.org/soap/encoding/'.
        at
org.apache.soap.util.xml.XMLJavaMappingRegistry.queryDeserializer(XMLJav
aMappingRegistry.java:206)
        at
org.apache.soap.util.xml.XMLJavaMappingRegistry.unmarshall(XMLJavaMappin
gRegistry.java:302)
        at
org.apache.soap.encoding.soapenc.ParameterSerializer.unmarshall(Paramete
rSerializer.java:206)
        at
org.apache.soap.util.xml.XMLJavaMappingRegistry.unmarshall(XMLJavaMappin
gRegistry.java:314)
        at
org.apache.soap.rpc.RPCMessage.unmarshall(RPCMessage.java:417)
        at
org.apache.soap.rpc.RPCMessage.extractFromEnvelope(RPCMessage.java:197)
        at
org.apache.soap.rpc.Response.extractFromEnvelope(Response.java:142)
        at GetChemDef.main(GetChemDef.java:167)


Here is the payload I got from the server:

<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope
xmlns:namesp2="http://xml.apache.org/xml-soap";
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/";
xmlns:xsi="http://www.w3.org/2001/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/2001/XMLSchema";><SOAP-ENV:Body><namesp17:ge
tAllInfoResponse
xmlns:namesp17="http://johnny5:8002/ChemDefServices";><s-gensym68
xsi:type="namesp2:SOAPStruct"><delimilator
xsi:type="xsd:string">|</delimilator><chemistry
xsi:type="xsd:string">caffeine</chemistry><a
xsi:type="xsd:string">aPiece</a><smiles
xsi:type="xsd:string">c1ccccc1</smiles><b
xsi:type="xsd:string">bPiece</b><syntaxOk
xsi:type="xsd:int">1</syntaxOk></s-gensym68></namesp17:getAllInfoRespons
e></SOAP-ENV:Body></SOAP-ENV:Envelope>


This payload refects a hashtable:

%h = ( chemistry => 'caffeine',
           a             => 'aPiece',
           b             => 'bPiece',
           smiles     => 'c1ccccc1'
         );

Here are the major code lines (as you can see, I was trying to use the
HashtableSerializer ):

        // build the call.
        Call call = new Call();
        call.setSOAPTransport(st);
 
call.setTargetObjectURI("http://localhost:8002/ChemDefServices";);
        call.setMethodName("getAllInfo");

        SOAPMappingRegistry smrr = new SOAPMappingRegistry ();
        HashtableSerializer hsd = new HashtableSerializer ();
        smrr.mapTypes(Constants.NS_URI_SOAP_ENC, new QName("",
"ChemDefServices"), Hashtable.class, null, hsd);

        // create the transport and set parameters
        call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC);
        call.setSOAPMappingRegistry(smrr);
        Vector params = new Vector();
        params.addElement(new Parameter("definition", String.class,
"definition", null));
        params.addElement(new Parameter("chemDefString", String.class,
chemDefString, null));
        call.setParams(params);

        // invoke it
        System.err.println("Invoking chemDef service at: ");
        System.err.println("\t" + serviceURL);
        Response resp;
        try {
            SOAPMappingRegistry smr = call.getSOAPMappingRegistry();
            SOAPContext reqCtx = call.getSOAPContext();
            DocumentBuilder xdb = XMLParserUtils.getXMLDocBuilder();

            Envelope callEnv = call.buildEnvelope();
            StringWriter payloadSW = new StringWriter();
            callEnv.marshall(payloadSW, smr, reqCtx);
            reqCtx.setRootPart(payloadSW.toString(),
                               Constants.HEADERVAL_CONTENT_TYPE);

            st.send(url, "", null, null, smr, reqCtx);

            SOAPContext respCtx = st.getResponseSOAPContext();
            String payloadStr = Call.getEnvelopeString(st);

            Document respDoc =    xdb.parse(new InputSource(new
StringReader(payloadStr)));
            Element payload = null;
            if (respDoc != null)            {
                payload = respDoc.getDocumentElement();
            }     else     {
                throw new SOAPException (Constants.FAULT_CODE_CLIENT,
                    "Parsing error, response was:\n" + payloadStr);
            }
            System.out.println("payloadStr = \n" + payloadStr);
           Envelope respEnv = Envelope.unmarshall(payload, respCtx);
            System.out.println("respEnv = \n" + respEnv.toString());
            System.out.println("respCtx = \n" + respCtx.toString());
            resp = Response.extractFromEnvelope(respEnv, smr, respCtx);
// I got error right here

Did I miss something to make it work?  Do I need to write my own
deseralizer for the hashtable?  If yes, how to incorporate the
deseralizer to the main funciton?

Thanks in advance,

Donald            

Reply via email to