ashutosh29jan / ksoap2-android

Automatically exported from code.google.com/p/ksoap2-android
0 stars 0 forks source link

Class Cast Exception when returning Object[] from .NET web service method #24

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?
1. Create a .net web service method GetAllCategories() which returns Category[] 
. Each Category is a class containing CategoryId (int) , Name (String) and 
Description (String)
2. Use this code
public static final String SOAP_ACTION = 
"http://vladozver.org/GetAllCategories";
    public static final String METHOD_NAME = "GetAllCategories";
    public static final String NAMESPACE = "http://vladozver.org/";
    public static final String URL = "http://192.168.1.3/Services/CategoryServices.asmx";
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        TextView tv = (TextView)findViewById(R.id.TextView01);

        SoapObject Request = new SoapObject(NAMESPACE, METHOD_NAME);
        Category C = new Category();
        C.CategoryId = 1;

        PropertyInfo pi = new PropertyInfo();
        pi.setName("Category");
        pi.setValue(C);
        pi.setType(C.getClass());
     //   Request.addProperty(pi);

        SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
        envelope.dotNet = true;
        envelope.setOutputSoapObject(Request);

        envelope.addMapping(NAMESPACE, "Category",new Category().getClass());
AndroidHttpTransport androidHttpTransport = new AndroidHttpTransport(URL);
try
        {
            androidHttpTransport.call(SOAP_ACTION, envelope);
SoapObject response = (SoapObject)envelope.getResponse();
Category[] res = new Category[response.getPropertyCount()];
            for (int i = 0; i < res.length; i++) {
     // THROWS EXCEPTION
                Category CTry = (Category)response.getProperty(i);
            }
catch(Exception e)
        {
            e.printStackTrace();
        }
}

public class Category implements KvmSerializable
{
    public int CategoryId;
    public String Name;
    public String Description;
    @Override
    public Object getProperty(int arg0) {

        switch(arg0)
        {
        case 0:
            return CategoryId;
        case 1:
            return Name;
        case 2:
            return Description;
        }

        return null;
    }
    @Override
    public int getPropertyCount() {
        // TODO Auto-generated method stub
        return 3;
    }
    @Override
    public void getPropertyInfo(int index, Hashtable arg1, PropertyInfo info) {
        // TODO Auto-generated method stub
        switch(index)
        {
        case 0:
            info.type = PropertyInfo.INTEGER_CLASS;
            info.name = "CategoryId";
            break;
        case 1:
            info.type = PropertyInfo.STRING_CLASS;
            info.name = "Name";
            break;
        case 2:
            info.type = PropertyInfo.STRING_CLASS;
            info.name = "Description";
            break;
        default:break;
        }
    }
    @Override
    public void setProperty(int index, Object value) {
        // TODO Auto-generated method stub
        switch(index)
        {
        case 0:
            CategoryId = Integer.parseInt(value.toString());
            break;
        case 1:
            Name = value.toString();
            break;
        case 2:
            Description = value.toString();
            break;
        default:
            break;
        }
    }
}

3. Run the code

What is the expected output? What do you see instead?
A category array with the returned categories. Instead a cast exception occurs. 
I don't know how to access the result set of a web service that returns an 
array of objects, in my case Category objects.

What version of the product are you using? On what operating system?
Latest, i downloaded it yesterday. Windows 7, Eclipse.

Please provide any additional information below.

Original issue reported on code.google.com by vladimir...@gmail.com on 19 Jun 2010 at 5:03

GoogleCodeExporter commented 9 years ago
Can you try with the latest 2.5.1 release and if it fails also append a stack 
trace?

Original comment by mosa...@gmail.com on 21 Oct 2010 at 4:46

GoogleCodeExporter commented 9 years ago

Original comment by mosa...@gmail.com on 21 Oct 2010 at 4:47

GoogleCodeExporter commented 9 years ago
Hello everybody.

I just want to say that I am having the same issue as described above. I did 
try the 2.5.1 release and the issue is the same. 

I have found descriptions of casting soap response to Vector when we have an 
array as a return web service type. But, envelope.getResponse() returns 
SoapPrimitive, so this casting results in a ClassCastException.  

Please fix this bug. kSoap library is really good but this bug is too heavy.

Original comment by nebe.dar...@gmail.com on 24 Oct 2010 at 7:09

GoogleCodeExporter commented 9 years ago
Nebe, I managed to make it work without the VECTOR class - please avoid it when 
returning an array of objects from web service.

Here you can see the complete tutorial I made:
http://seesharpgears.blogspot.com/2010/10/ksoap-android-web-service-tutorial-wit
h.html

Original comment by vladimir...@gmail.com on 24 Oct 2010 at 11:09

GoogleCodeExporter commented 9 years ago
Thanks for the blog post. I have put a link to it onto the wiki links section. 
Can I close this issue therefore?

Original comment by mosa...@gmail.com on 25 Oct 2010 at 4:12

GoogleCodeExporter commented 9 years ago
Sure, go ahead

Original comment by vladimir...@gmail.com on 25 Oct 2010 at 7:34

GoogleCodeExporter commented 9 years ago
Vladimir,
thanks for this tutorial. It solved one problem. But there is one that is still 
there. When web service returns array of primitive types, kSoap only returns 
first value in array. This is my code:

Web Service method:
-------------------
@WebMethod(operationName="getInts")
public int[] getInts()
{
    return new int[] {4,5,6};
}

Android app:
------------
.
.
. SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
            SoapSerializationEnvelope envelope =
            new SoapSerializationEnvelope(SoapEnvelope.VER11);
            //envelope.dotNet = true;
            envelope.setOutputSoapObject(request);
            AndroidHttpTransport androidHttpTransport = new AndroidHttpTransport(URL);
            androidHttpTransport.call(SOAP_ACTION, envelope);

            SoapObject s = (SoapObject)envelope.getResponse(); //here, SoapPrimitive is returned. If I use envelope.getResponse().toString() only first number, in this case 4, is there

Thank you once again for your posts. It really helped me. This other issue is 
to be solved by using bodyIn, but it would be good if kSoap could work in both 
cases.

Best regards,
Nebojsa (or Nebe)

Original comment by nebe.dar...@gmail.com on 25 Oct 2010 at 5:52

GoogleCodeExporter commented 9 years ago
One thing that comes to my mind is to write a code like the following:

public static int[] RetrieveFromSoap(SoapObject soap)
    {
        int[] numbers = new int[soap.getPropertyCount()];
        for (int i = 0; i < numbers.length; i++) {
            SoapObject pii = (SoapObject)soap.getProperty(i);
            numbers[i] = Integer.parseInt(pii.getProperty(0).toString());
        }
        return numbers ;
    }
If this does not work (though it should, but I did not test it in Eclipse yet), 
then you should maybe create wrapper classes for primitive types, e.g. create a 
class that has only one property which is int, and then return an array of such 
objects, just as I do in the example with the Categories in the tutorial.

Original comment by vladimir...@gmail.com on 25 Oct 2010 at 6:27

GoogleCodeExporter commented 9 years ago
Hi, once again.

I have finally figured out how to cope with this problem. The main bug is 
actually in SoapSerializationEnvelope's method getResponse(). Here is the code 
of this method:

public Object getResponse() throws SoapFault {
        if (bodyIn instanceof SoapFault) {
            throw (SoapFault) bodyIn;
        }
        KvmSerializable ks = (KvmSerializable) bodyIn;
        return ks.getPropertyCount() == 0 ? null : ks.getProperty(0);
}

As you can see, this method returns only the first property. Work around is to 
use KvmSerializable. Here is an example:

SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
            SoapSerializationEnvelope envelope =
            new SoapSerializationEnvelope(SoapEnvelope.VER11);
            //envelope.dotNet = true;
            envelope.setOutputSoapObject(request);
            AndroidHttpTransport androidHttpTransport = new AndroidHttpTransport(URL);
        androidHttpTransport.call(SOAP_ACTION, envelope);

                KvmSerializable ks = (KvmSerializable)envelope.bodyIn;
                for(int i=0;i<ks.getPropertyCount();i++)
                {
                   ks.getProperty(i); //if complex type is present then you can cast this to SoapObject and if primitive type is returned you can use toString() to get actuall value.
                }

Best regards to you all,
Nebe

Original comment by nebe.dar...@gmail.com on 27 Oct 2010 at 1:00

GoogleCodeExporter commented 9 years ago
Hey nebe.daredevil, i am trying to use as you said, i am returning a complex 
object, and i am putting like this:

SoapObject soap= (SoapObject) ks.getProperty(i);

But i dont get nothing... 

Original comment by sauron.i...@gmail.com on 28 Oct 2010 at 10:21

GoogleCodeExporter commented 9 years ago
Was able to get it done like this:

String response= (String) ks.getProperty(i).toString();

And now parse the response. Thanks nebe you are a god among humans...

Original comment by sauron.i...@gmail.com on 28 Oct 2010 at 10:43

GoogleCodeExporter commented 9 years ago
Hehe... I was just about to respond to your question. 

Thank you for all that praise. I just spent a lot of time on this problem, that 
is all.

Anyway: try to get cast to SoapObject and then get its properties. I think that 
it would be a faster way to get it parsed. 

SoapObject soap = (SoapObject)ks.getProperty(i);
String tmp = soap.getProperty(0).toString();

Original comment by nebe.dar...@gmail.com on 28 Oct 2010 at 11:02

GoogleCodeExporter commented 9 years ago
It was not an issue with ksoap but with the code using the library and the 
problem was figured out in the discussion here.

Original comment by mosa...@gmail.com on 29 Oct 2010 at 10:41

GoogleCodeExporter commented 9 years ago
It IS kSoap problem. See my post about it. getResponse is method producing this 
problem.

Original comment by nebe.dar...@gmail.com on 30 Oct 2010 at 2:43

GoogleCodeExporter commented 9 years ago

Original comment by mosa...@gmail.com on 1 Nov 2010 at 9:56

GoogleCodeExporter commented 9 years ago
Ok.. that was a misunderstanding then. So if you have a fix I will apply the 
patch and we can do a new release when you want.

Original comment by mosa...@gmail.com on 1 Nov 2010 at 9:57

GoogleCodeExporter commented 9 years ago
Ok.I'm a bit busy right now and also quite new to this so if you can please 
tell me what is the correct way to apply this fix. Should I send it to your 
e-mail? Is it enough to send just code that would fix the mentioned method?

Original comment by nebe.dar...@gmail.com on 2 Nov 2010 at 7:24

GoogleCodeExporter commented 9 years ago
OK. I think I have uploaded changes on github. Can you please check if I have 
done everything correctly. I cloned repo, did changes and commit everything. 
Author name is unknown because I didn't know how to change this. 

Original comment by nebe.dar...@gmail.com on 2 Nov 2010 at 1:35

GoogleCodeExporter commented 9 years ago
The changes look good. I will pull them into upstream. 

Original comment by mosa...@gmail.com on 2 Nov 2010 at 3:40

GoogleCodeExporter commented 9 years ago
The changes are now in the master on github. Can I therefore close this issue? 

Original comment by mosa...@gmail.com on 2 Nov 2010 at 3:44

GoogleCodeExporter commented 9 years ago
As far as I'm concerned - close it. Thank you for your time. 

Original comment by nebe.dar...@gmail.com on 2 Nov 2010 at 3:59

GoogleCodeExporter commented 9 years ago
Could you provide the direct link of the source on GitHub prior closing it ?

Original comment by vladimir...@gmail.com on 2 Nov 2010 at 4:13

GoogleCodeExporter commented 9 years ago
see http://code.google.com/p/ksoap2-android/wiki/SourceCodeHosting?tm=4

Original comment by mosa...@gmail.com on 3 Nov 2010 at 7:36

GoogleCodeExporter commented 9 years ago
Use 
SoapObject response = (SoapObject)envelope.bodyIn();

Insted of
SoapObject response = (SoapObject)envelope.getResponse();

Works for me

Thanks Ishara

Original comment by iudaya...@gmail.com on 29 Mar 2011 at 2:27

GoogleCodeExporter commented 9 years ago
Hi everybody.
Maybe you all wonder, but I can not get an array of byte from ksop2.
I read all of articles and GitHub, but ...
my senario is so simple,
I have a method named getApp in my server side :
public byte[] getApp(){

return an array of bytes;

}

And I am calling it from my android app in client side :

after calling the call method, what should I do for getting my byte array ?

        SoapObject request = getSoapObject(MethodName, inputs);
        SoapSerializationEnvelope envelope = getEnvelope(request);
         makeCall(URL, envelope, NAMESPACE, MethodName);

    private static Vector<Object> makeCall(String URL,
            SoapSerializationEnvelope envelope, String NAMESPACE,
            String METHOD_NAME) {
        HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
        try {

            androidHttpTransport.call(NAMESPACE + "/" + METHOD_NAME, envelope);
            Vector<Object> responseVector = null;
            SoapObject response = null;

            if (envelope.getResponse() instanceof Vector) {
                responseVector = (Vector<Object>) envelope.getResponse();
            } else {
                System.out.println("I have in single soap object                if (envelope.getResponse() instanceof SoapObject) {

                    response = (SoapObject) envelope.getResponse();
                    responseVector = new Vector<Object>(1);
                    responseVector.add(response);

                } else if (envelope.getResponse() instanceof Integer) {

                    Integer res = (Integer) envelope.getResponse();
                    responseVector = new Vector<Object>(1);
                    responseVector.add(res);

                } 
                else if (envelope.getResponse() instanceof SoapPrimitive) {

//my problem is here , my response here is instance of SoapPrimitive 

what should I do in here for getting my byte array from soap ????
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

Best Regards,
M.Sh

Original comment by mahdisha...@gmail.com on 13 Mar 2012 at 9:50

GoogleCodeExporter commented 9 years ago
You should not call getResponse multiple times for starters. Just get it as an 
Object and then do you instanceof tests .. for the SoapPrimitive just get the 
value and parse it. 

Original comment by mosa...@gmail.com on 21 Mar 2012 at 10:55

GoogleCodeExporter commented 9 years ago
Hello,

I read all above articles but I couldn't found a solution for my problem:
Simply I am calling a .net webservice method that returns an array of string:
but in java eclipse I m not able to retrieve all values in the array. here is 
my code:

 [WebMethod]
    public string[] GetAllRecords(string supcode)
    {

             string dbname = "db";
             string badgeno = "";
        SqlConnection con = new SqlConnection(@"Data Source =xxx ; user id=xxxx  ; password=xxxx; Initial Catalog = " + dbname + ";");

        con.Open();

        string strQuery = "select distinct xx from tbl where cperiod='201208' and  code='" + supcode + "'";

        DataSet ds = new DataSet();
        SqlDataAdapter da = new SqlDataAdapter(strQuery, con);
        da.Fill(ds);
        con.Close();
        List<string> cityList = new List<string>();
        for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
        {

            cityList.Add(ds.Tables[0].Rows[i]["xx"].ToString());

        }
        con.Close();
        return cityList.ToArray();

    }

eclipse Java code:

package com.example.app;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;

import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;

import com.example.timesheetapp.R;
import android.widget.Button;
import android.widget.EditText;
//import android.app.*;
//import android.os.*;
import android.widget.TextView;

import android.view.View.OnClickListener;

public class MainActivity extends Activity implements OnClickListener  {

    private static final String SOAP_ACTION = "http://tempuri.org/DBconnect";

    private static final String METHOD_NAME = "GetAllRecords";

    private static final String NAMESPACE = "http://tempuri.org/";
    private static final String URL = "http://ip/mywebservice/Service1.asmx";
    TextView tv;
    EditText ed;

     @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tv=(TextView)findViewById(R.id.txt1);
        ed=(EditText)findViewById(R.id.editText1);
        Button b=(Button)findViewById(R.id.button1);
        b.setOnClickListener(this);
    }

     @Override
    public void onClick(View V) {
        // TODO Auto-generated method stub
         call();    
    }
    public void call()
    {
        try {

            SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);

          request.addProperty("supcode", ed.getText().toString());

           SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
          envelope.dotNet=true;
           envelope.setOutputSoapObject(request);

           HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
          androidHttpTransport.call(SOAP_ACTION, envelope);

            Object result = (Object)envelope.getResponse();

            tv.setText(result.toString());

        } catch (Exception e) {
            tv.setText(e.getMessage());
            }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }

}

Original comment by tarekfa...@gmail.com on 7 Feb 2013 at 10:31

GoogleCodeExporter commented 9 years ago
[deleted comment]
GoogleCodeExporter commented 9 years ago
[deleted comment]
GoogleCodeExporter commented 9 years ago
I got nothing during adding header in soap.

Here is my code:

package com.dharma;

import org.ksoap2.SoapEnvelope;
import org.ksoap2.SoapFault;
import org.ksoap2.serialization.PropertyInfo;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapPrimitive;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;
import org.kxml2.kdom.Element;
import org.kxml2.kdom.Node;

import com.dharma.Test.SoapTask;
import android.app.Activity;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class SOAP_WebService extends Activity
{
     String test_string=null;

        private int TIME_OUT=50000;
        private static final String METHOD_NAME = "DoWork";
        private static final String NAMESPACE = "http://tempuri.org/";
        //private static final String URL = "http://192.168.169.133/WFPeWin2/content/WFPService.svc";
        //private static final String URL = "http://192.168.169.133/WebServiceRnD/ComplexCustomHeaderService.svc";
        private static final String URL = "http://192.168.169.133/WCFSvc/SimpleCustomHeaderService.svc";
        User U = new User();
        //private static final int SOAP_VERSION = SoapEnvelope.VER11;
        private static final String SOAP_ACTION = "http://tempuri.org/ISimpleCustomHeaderService/DoWork";

    public void onCreate(Bundle savedInstanceState) 
    {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.test);
         new SoapTask().execute();
    }
    public class SoapTask extends AsyncTask<Void, Void, Void> {
        private final ProgressDialog    dialog  = new ProgressDialog(SOAP_WebService.this);

        protected void onPreExecute() {

            this.dialog.setMessage("Checking in...");
            this.dialog.show();

        }

        @Override
        protected Void doInBackground(Void... arg0) {
            try{
                test_string=callSOAPWebService();
            }catch (Exception e){
                e.printStackTrace();
            }
            return null;
        }

        protected void onPostExecute(Void result) {
            TextView tv = (TextView) findViewById(R.id.Result);
            tv.setText(test_string);

            if (this.dialog.isShowing()){
                this.dialog.dismiss();
            }
        }

    }
    public String callSOAPWebService()
    {
        String returnString=null;
        SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
       // PropertyInfo sendProp =new PropertyInfo();
        //sendProp.name = "iNum";
       // sendProp.setValue(44);
      //  request.addProperty(sendProp);
        String soapEnvelope = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd";
        SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);

       /* Element[] header = new Element[1];
        header[0] = new Element().createElement("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd","Security");

        Element ws = new Element().createElement(null, "web-user");
        ws.addChild(Node.TEXT, "First");

        Element wni = new Element().createElement(null, "web-node-id");
        wni.addChild(Node.TEXT,"Second");

        Element wsi = new Element().createElement(null, "web-session-id");
        wsi.addChild(Node.TEXT,"Third");

        header[0].addChild(Node.ELEMENT, ws);
        header[0].addChild(Node.ELEMENT, wni);
        header[0].addChild(Node.ELEMENT, wsi);*/

        // add header to envelope
       // envelope.headerOut = header;
        envelope.headerOut = new Element[1];
        envelope.headerOut[0] = buildAuthHeader();

        Log.i("header", "" + envelope.headerOut.toString());

        envelope.dotNet = false;
        envelope.bodyOut = request;
        envelope.setOutputSoapObject(request);
        HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
        Log.i("bodyout", "" + envelope.bodyOut.toString());

        try 
        {
            androidHttpTransport.debug = true;
            androidHttpTransport.call(SOAP_ACTION, envelope);

            SoapPrimitive response = (SoapPrimitive)envelope.getResponse();
            returnString=response.toString();
            Log.i("myApp", response.toString());
        } 
        catch (SoapFault e)
        {
            e.printStackTrace();
        }
        catch (Exception e) 
        {
            e.printStackTrace();
            Log.d("Exception Generated", ""+e.getMessage());
        }
        return returnString;

    }
    private Element buildAuthHeader() {
         Element h = new Element().createElement(NAMESPACE, "AuthHeader");
            Element first = new Element().createElement(NAMESPACE, "web-user");
            first.addChild(Node.TEXT, "web_user_name");
            h.addChild(Node.ELEMENT, first);

            Element second = new Element().createElement(NAMESPACE, "web-node-id");
            second.addChild(Node.TEXT, "web_node_id");
            h.addChild(Node.ELEMENT, second);

            Element third = new Element().createElement(NAMESPACE, "web-node-id");
            third.addChild(Node.TEXT, "web_node_id");
            h.addChild(Node.ELEMENT, third);

            return h;
    }

}

I have empty value, it means nothing added on header or any other. It is write 
my coding adding header info.

please , I am spending lots of hour during adding header in soap. please give 
some idea.

Original comment by dharma.k...@gmail.com on 23 Apr 2014 at 10:19