Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Doubt about namespaces, nil values, etc #8

Open
nobre84 opened this issue Jul 5, 2013 · 8 comments
Open

Doubt about namespaces, nil values, etc #8

nobre84 opened this issue Jul 5, 2013 · 8 comments

Comments

@nobre84
Copy link

nobre84 commented Jul 5, 2013

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
Copy link
Owner

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
Copy link

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:

  • How would you get the source object's namespace? First, I presume, I'd need to set the correct namespace annotation in the generated java source files, and then, in the writeObject(), somehow make use of that?
  • Would it be possible to alter the element names and prepend the namespace short aliases?

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
Copy link
Owner

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
Copy link
Author

nobre84 commented Jul 18, 2013

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
Copy link
Owner

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
Copy link

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
Copy link
Author

nobre84 commented Jul 24, 2013

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
Copy link

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>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants