Attribute support for KSOAP2 on Android

So recently I have been doing a lot of Android development and generally having a great time. In general the Android API is very complete and offeres support for a whole lot of features and task. I did however have to find out that SOAP support is generally non existant. Given the widely known problems with SOAP and the trend towards simpler REST based services and the young age of the Android platform this is not too surprising. However in reality lots people still need to work with (legacy?) SOAP services. If you are in that situation you should read on.

When you research on the web for SOAP support libraries on embedded devices including Android you end up running into KSOAP and KSOAP2. Coming from a J2ME background this library is used on RIM Blackberry, other J2ME devices and now Android. For Android specifically there is a little project that converted the build to Maven and applied some patches for Android. It seems to be the preferred goto resource for KSOAP2 and Android. Unfortunately everything around KSOAP seems to be rather old and inactive. The project has a few issues assigned and had no activity for a while. But if you can read the code you can fix it to. In particular I found that xml attributes are not supported for normal parsing when no automatic marshalling is used. This has been noticed by people before and supposedly a patch to fix it has been applied. Problem is it did not do the trick for me and others. So I went ahead and fixed the issue. In the following I will show you how to get the patched source code, build it and use it in a Android project built with Maven as well as a regular Android project.

Ok I assume you still have not lost me in the technicalities so I am going to dive right in. Let’s go and get the source from my git fork on github. You can either just download a tar.gz or zip file with the source from the site directly or clone it onto your computer with git

 git clone git://github.com/mosabua/ksoap2-android.git

Once you got the source you need to build it following the simple Maven convention.

cd ksoap2-android
mvn clean install

This will take more or less time depending on your Maven version as well as what dependencies you have already downloaded into your local Maven repository. For me it just took 9 seconds.

Now provided you are building your Android project with Maven your got all necessary dependencies already in your repository thanks to the build you just did. So you just need to add the dependency to your Android project pom.xml file.

        <dependency>
            <groupId>com.google.code.ksoap2-android</groupId>
            <artifactId>ksoap2-android</artifactId>
            <version>2.5-SNAPSHOT</version>
        </dependency>

If you are however building your project with ant or eclipse you need to take the assembly file ksoap2-android/ksoap2-assembly/target/ksoap2-android-assembly-2.5-SNAPSHOT-jar-with-dependencies.jar and put it to the a newly created libs folder inside your project. Then you will have to add it to the classpath in Eclipse. If you need more info, read more about adding external libraries and building with ant on the Android developer site. Oh and if you really dont want to build the library yourself you can download it as from this site as well.

After you have added the dependency to your project and setup your request and start parsing your response you will notice that in contrary to the prior code the getAttribute method will actually return the attributes as existant in the response xml. You will be able to do all the usual parsing you already do with properties retrieved with getProperty.

Ideally you would not have to use my fork or even build the library yourself. Unfortunately I seem to be unable to receive feedback from the project owner on the Google Code site. If you are Karl M Davies… please contact me. It would be great to see my patch applied to the main branch and maybe even see the artifacts deployed to Maven central. But that is another story…

UPDATE (2010-10-20): I have taken over the ksoap2-android project on google code as project owner and cut a new release that contains this and other improvements. More details are on my announcement blog post.

28 comments » Write a comment

  1. YOU ARE GOD!!!!!

    I’ve been working with this ksoap2-android-full-2.1.2.jar for months now and it’s a mess. I rly would like to work with risk, but unfortunately I’m stuck with some old web-services.

    Anyway, I don’t know how these libraries are licenced but if you get sued or smthing over it, contact me, maybe I can spare a few bucks 😀 😀 😛

    Thank u very much.

  2. Hi again!

    I tried the library on something like this:

    Phone, Smart

    (510)170-3292
    (510)206-3260

    I’m obviously interested in fetching those “sType” attributes from the “cPhoneNum” tags. And….I can’t. The SoapObject object for “cPhoneNum” claims it doesn’t have any attributes.
    Could you please give us a small working example of how to get hold of the attributes?

    Thank u

  3. Aaaaargh! I will rewrite that.

    (GetDemographicsResult)
    (sMD)Phone, Smart(/sMD)
    (aoPhones)
    (cPhoneNum sType=”Home”)somephonenr1(/cPhoneNum)
    (cPhoneNum sType=”Work”)somephonenr2(/cPhoneNum)
    (/aoPhones)
    (/GetDemographicsResult)

    I repeat the last part of my message to:

    I’m obviously interested in fetching those “sType” attributes from the “cPhoneNum” tags. And….I can’t. The SoapObject object for “cPhoneNum” claims it doesn’t have any attributes.
    Could you please give us a small working example of how to get hold of the attributes?

    Thank u

  4. IMHO the best way to figure out how to retrieve the attributes (and properties too actually) is to put a breakpoint straight where you get the raw response from httpclient in your code.

    Then you can just browse through the structure with your debugger and try retrieving the values you are looking for by chaining getProperty(“somename”) and getAttribute(“someothername”) the way you need. You will often need to access parts of the structure by getting some property as a SoapObject and then e.g. looping through its properties and getting the attributes from each. All depends on your structure.

  5. Hi manfred.

    I am using KXmlParser.java from the “ksoap2-android-assembly-2.5-SNAPSHOT-jar-with-dependencies.jar” library (which I got from the ksoap2-android-assembly\target folder after running maven on the ksoap2-android project).
    The raw xml contains the attributes, but the XML document that I get after parsing the input stream, doesn’t contain any attributes. Only elements appear.

    More specifically the raw input looks like this:

    (sOfficeName sOfficeID=”LID_3″) <– note the attribute
    Los Altos Office <– this is a simple text element
    (/sOfficeName)

    and what I get is a SoapPrimitive having it's value set to "Los Altos Office".

    If anybody has a working example of the ksoap2-android-assembly-2.5-SNAPSHOT-jar-with-dependencies.jar please send it to gabor.biro@arobs.com. Please!!!

    Gabor out

  6. Somewhere in the code you will have something along the lines of
    androidHttpTransport.debug = true;
    androidHttpTransport.call(getSoapAction(), envelope);
    Object response = null;
    response = envelope.getResponse();

    with try catch stuff omitted. With the debug true setting you can look at
    androidHttpTransport.requestDump and responseDump to confirm that you getting the right request and response. If you see the attributes in the response you can continue to
    look at the next sort of code and set a breakpoint just after the getResponse() call.

    response is object because it could be SoapObject or SoapPrimitive but unfortunately they have no shared parent class or interface so you have to use object (bad design in ksoap…)

    Provided the getResponse call did not throw some exception you will be able to parse through the structure of the response object and you will find the properties and attributes there. In your case there something along the lines of getProperty(“sOfficeName”).getAttribute(“sOfficeID”) should get you a value od LID_3.

  7. Thanks for your reply.

    I eventually got hold of the ksoap2 librarys’ source code, did some deep debugging and solved the problem by using Marshal objects. Well actually a tricky compination of soap-mappings and Marshal objects.

    If anybody wants to know more, drop a line to gabor.biro@arobs.com

    Thanks, everybody

  8. Yes.. that patch is applied. But yes… it still does have problems with soapfault parsing. I have not taken the time to figure out whats up there. If anybody has a patch I am willing to apply and republish.

  9. Hi, thanks a lot for this patch!

    Since you are pretty familiar with KSOAP2 for Android, I take the opportunity to ask one more question (unfortunately I could not find any examples on the web).

    How is it possible to parse next complex types?

    For example:
    class Person {
    String firstName;
    Address address;
    }
    class Address {
    String city;
    String zipCode;
    }

    I can have both Person and Address implement the KvmSerializable interface. And then addMapping() of the Person to the SoapEnvelope.

    Yet, it does not work.

    How to implement the Person KvmSerializable interface properly?

    Or should I also make use of the Marshal interface?

    Thanks for your time!

    Best Regards, Andrea

  10. Andrea,

    I played around with KvmSerializable and MArshalling for a while and found it to be too intrusiv. I wanted my pojos to stay independent of ksoap so I ended up not going along that approach although I have seen others using it successfully.

    I just parse the xml response and build up the pojos manually with getProperty and getAttribute. This allows me full control of how I assemble my pojos too. In fact my pojo are not even proper java beans since I expose the properties as public…

  11. Hi Manfred,

    Thanks for your reply.

    In my case I achieved independence from the protocol by introducing a remote service interface. ksoap remains just but one of the possible implementations of the service interface. In the end, the rest of the application only knows the pojos that are “produced” by the service.

    Coming to the SOAP service implementation, I thought ksoap could save me some time.
    Deserializing the object is not a problem. But serializing it (ie. addProperty() sending the request) remains a problem. In the example above, the request is formatted like this:
    { …; person=com.amelie.examples.soap.Person@44f34468; …}

    ksoap is just writing the reference to the Person instance, and not all its properties, although the Person implements the KvmSerializable interface.

    Maybe I should experiment with Marshal. I am not sure.

  12. For the request generation I also just add properties from for the various parameters and build up the request from my pojos manually.. but yes.. marshalling should do the trick for you unless you object tree is too complex..

  13. Nice one! I’ll need the attribute reading support for the response of the webservice I’m using.

    But first I’ll need to add attributes to elements in my request. Is this possible?

  14. Yes. You can build up the body with attributes and properties already out of the box of the normal distribution.

  15. Hi, sir!
    I’m using kSoap2 to deal with web service, but I have encountered a problem.
    That is how to add a attribute to a property?
    I mean, look at this : how can I add the id attribute to the property?
    Great thanks!!!

  16. Like I said you can build up your request body with attributes and properties already. What do you want me to look at?

  17. I’m having the same problem Arlecchino mentioned: The XML returned contains attributes, but those attributes don’t appear anywhere in the SoapObject returned by envelope.getResponse().

    The output of transport.responseDump follows

    {SOAP-ENV:Envelope xmlns:SOAP-ENV=’http://schemas.xmlsoap.org/soap/envelope/’ xmlns:xsi=’http://www.w3.org/2001/XMLSchema-instance’ xmlns:s=’http://www.w3.org/2001/XMLSchema’}
    {SOAP-ENV:Body}
    {TheResponse xmlns=”http://default.org”}{Result}{Item Key=”Alpine Urgent Care”}2{/Item}{Item Key=”Broadmoor Urgent Care”}1{/Item}{/Result}{/Response}

    anyType{Item=2; Item=1; Item=2; Item=2; Item=1; }
    Specialties Query:

    It appears the problem is that the data for Item is primitive and not another property.

    Are there any known work-arounds?

  18. I’ve had a chance to look through the source code and I see the problem:
    In SoapSerializationEnvelope, attributes get added to a SoapObject when a nested start tag is detected:

    if (parser.getEventType() == XmlPullParser.START_TAG)
    {
    if (text != null && text.trim().length() != 0)
    {
    throw new RuntimeException(“Malformed input: Mixed content”);
    }
    SoapObject so = new SoapObject(typeNamespace, typeName);
    // apply all the cached attribute info list before we add the property and descend further for parsing
    for (int i = 0; i < attributeInfoArrayList.size(); i++) {
    so.addAttribute(attributeInfoArrayList.get(i));
    }

    If an element contains text instead of a nested start tag (e.g., {myElement name="Fred"}Barney{/myElement}), then SoapSerializationEnvelope creates and returns a SoapPrimitive object. The attributeInfoArrayList is simply discarded.

  19. Hey Manfred,

    Got the request for a ComplexType working (including attribute support). Now I’m stuck at deserializing the (ComplexType) response I’m receiving.

    You talked about parsing the XML response. Have you got some samplecode which could give me a head start?

    Thanks for the support so far.

  20. Pingback: Reviving ksoap2 for Android | simpligility

  21. Hi Manfred,

    I have sucessfully done basic authentication in blackberry by adding HttpTransportBasicAuth class to Ksoap2 lib?
    Please let me know how to do the same in Ksoap2-andorid jar.

    Thanks for your help in advance.

    regards
    venke

  22. Thanks a lot!! I was looking for this only!!.
    Your library helped me!!

  23. The method above receives one line of string from the result object, and a class, that has public members. To be able to map the SOAP response values with the corresponding members.

  24. Not having much luck with writing tags in my message.
    String xml is:
    Opening Tag property1 = /”/” property2 = /”/” Closing Tag

Leave a Reply

Required fields are marked *.