bulldog2011 / nano

A light Android web serivce client framework
Apache License 2.0
33 stars 30 forks source link

Doubt about namespaces, nil values, etc #8

Open nobre84 opened 11 years ago

nobre84 commented 11 years ago

Hi, I'm trying to consume an API, the soap envelope generated by Nano looks like this:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://tempuri.org/">
    <soapenv:Body>
        <CreateQueryStrings_Start>
            <userId>1234</userId>
            <password>abcd</password>
            <idOrgao>57</idOrgao>
            <numeroProcesso>1</numeroProcesso>
            <inputParameters>
                <ParameterList>
                    <Parameter>
                        <Name>TipoConsulta</Name>
                        <Value>Precatórios / Beneficiário</Value>
                    </Parameter>
                </ParameterList>
            </inputParameters>
        </CreateQueryStrings_Start>
    </soapenv:Body>
</soapenv:Envelope>

It returns incorrect results from the WCF webservice. The same input form is enveloped as this by a .NET MVC application:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <s:Body>
        <CreateQueryStrings_Start xmlns="http://tempuri.org/">
            <userId>1234</userId>
            <password>abcd</password>
            <idOrgao>57</idOrgao>
            <numeroProcesso>1</numeroProcesso>
            <inputParameters xmlns:a="schemas.datacloud.novaprolink.com.br/IWSConsultaProcesso" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
                <a:ParameterList>
                    <a:Parameter>
                        <a:Description i:nil="true"/>
                        <a:Name>TipoConsulta</a:Name>
                        <a:PossibleValues i:nil="true" xmlns:b="http://schemas.microsoft.com/2003/10/Serialization/Arrays"/>
                        <a:SuggestedValues i:nil="true" xmlns:b="http://schemas.microsoft.com/2003/10/Serialization/Arrays"/>
                        <a:Value>Precatórios / Beneficiário</a:Value>
                    </a:Parameter>
                </a:ParameterList>
            </inputParameters>
        </CreateQueryStrings_Start>
    </s:Body>
</s:Envelope>

What could be the reason it won't work ? Maybe the namespacing ? Nil value objects that aren't being encoded ? The wsdl is: http://wsrobos.novaprolink.com.br/v2/WSConsultaProcessos.WSConsultaProcesso.svc?wsdl

Regards nobre

bulldog2011 commented 11 years ago

Hi,

Nano is just a light library targeting Android platform, considering the complexity introduced, it only supports a single target namespace.

In your case, as workaround, I recommend you to do some hacking to the nano source, the code logic of nano is not complicated, hope you can make it:

  1. To support nested namespace, you may try to hack the source of XmlPullWriter.java https://github.com/bulldog2011/nano/blob/master/src/main/java/com/leansoft/nano/impl/XmlPullWriter.java you may try to update the function: protected void writeObject(XmlSerializer serializer, Object source, String namespace) throws Exception extract namespace from the object, compare it with the namespace passed in, if not equal, use the extracted namespace instead.
  2. To minimize xml message size, Nano does not serialize null field, but you can serialize null field as needed by hacking the source of XmlPullWriter.java

Let me know if you need additional help.

Thx! -William

artjomsimon commented 11 years ago

Hi William,

could you elaborate on that a little more; I'm in the same situation trying to talk to a .net webservice, where nested namespaces seem to be used quite often.

I've looked into the XmlPullWriter.java, and have several questions:

I'm trying to produce something along those lines:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:tempuri="http://tempuri.org/"
xmlns:datacontract="http://schemas.datacontract.org/2004/07/SomeDataModel.Model">
   <soapenv:Body>
      <tempuri:GetPermissions>
         <tempuri:login>
            <datacontract:LoginName>user</datacontract:LoginName>
            <datacontract:Password>pass</datacontract:Password>
         </tempuri:login>
      </tempuri:GetPermissions>
   </soapenv:Body>
</soapenv:Envelope>

Thank you for any hints!

bulldog2011 commented 11 years ago

Hi,

see my comments below:

  1. namespace is extracted from object using code like:
MappingSchema ms = MappingSchema.fromObject(source);
RootElementSchema res = ms.getRootElementSchema();
String namespace = res.getNamespace();
  1. namespace is auto-annotated on chasses during code generation, not all classes will have namespace annotations, it depends on the schema definition. it is not recommended that you annotate your class with namespace manually.
  2. It is possible to alter the element names and prepend the namespace short alias, however this is not recommended, I recommend you to do following to support nested namespace: in the source of XmlPullWriter.java https://github.com/bulldog2011/nano/blob/master/src/main/java/com/leansoft/nano/impl/XmlPullWriter.java you may try to update the function:
protected void writeObject(XmlSerializer serializer, Object source, String namespace) throws Exception

Extract namespace from the object, if not empty, compare it with the namespace passed in, if not equal, use the extracted namespace instead.

Thx! -William

nobre84 commented 11 years ago

I have added this in XmlPullWriter.writeObject method: MappingSchema ms = MappingSchema.fromObject(source); String innerNamespace = ms.getRootElementSchema().getNamespace(); if (innerNamespace != null && !innerNamespace.equals(namespace)) { namespace = innerNamespace; }

Is there any problem in this approach that would prevent this behavior to be added to the library ?

About the empty objects, I started doing a patch to the writeElement method to handle it , but it didn't work very well when adding attributes to the xml. And in fact it was pointless as the namespaces were enough to make it work as intended and with a smaller xml output.

bulldog2011 commented 11 years ago

Thx for your work and feedback, I plan to integrate the nested namespace logic into the latest source, will let you know when done.

-William

artjomsimon commented 11 years ago

Thank you both! With your help, I finally managed to get my client to talk to a WCF web service.

The only difference from my WCF reference implementation is that the native client declares all the namespace in the head:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:tempuri="http://tempuri.org/"
xmlns:datacontract="http://schemas.datacontract.org/2004/07/SomeDataModel.Model">
   <soapenv:Body>
      <tempuri:GetPermissions>
         <tempuri:login>
            <datacontract:LoginName>user</datacontract:LoginName>
            <datacontract:Password>pass</datacontract:Password>
         </tempuri:login>
      </tempuri:GetPermissions>
   </soapenv:Body>
</soapenv:Envelope>

whereas my solution using the modified XmlPullWriter (which isn't suited for this kind of refactoring, I presume) trivially writes the namespace on each element again:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns="http://tempuri.org/">
   <soapenv:Body>
      <GetPermissions>
         <login>
            <n0:LoginName xmlns:n0="http://schemas.datacontract.org/2004/07/SomeDataModel.Model">user</n0:LoginName>
            <n1:Password xmlns:n1="http://schemas.datacontract.org/2004/07/SomeDataModel.Model">pass</n1:Password>
         </login>
      </GetPermissions>
   </soapenv:Body>
</soapenv:Envelope>

It works, but is rather verbose, especially if several children use the same namespace, which has an even higher impact on a mobile uplink.

I could mitigate this by using gzip (which is a good idea anyways), but that only works if I have control over the server's configuration.

Is this a limitation of the current nano/XmlPullParser implementation we're dealing with here, or am I doing something wrong?

Thanks for your support again!

nobre84 commented 11 years ago

I ran into that issue as well, but I think in the current implementation it would be difficult to pre-declare the namespaces, unless one would traverse the hierarchy beforehand just to collect all the inner namespaces.

marckaraujo commented 11 years ago

How to get off this n0, n1, n2 when you put namespaces?

<login>
            <n0:LoginName xmlns:n0="http://schemas.datacontract.org/2004/07/SomeDataModel.Model">user</n0:LoginName>
            <n1:Password xmlns:n1="http://schemas.datacontract.org/2004/07/SomeDataModel.Model">pass</n1:Password>
         </login>