kSoap2 POJO mapping class cast exception

805 views Asked by At

I have difficulties using kSOAP2 library for android. I am able to send requests and get the response, but I would like to map the contents of the response to a plain java object. Basically kSOAP2 allows you to do that by specifying the parameters of the mapping into the addMapping() method. Anyway I am having a class cast exception when trying to cast the response to my Java object. Here is my implementation :

final SoapSerializationEnvelope envelope = LoginInfo.buildLoginObject(login,password);
envelope.addMapping(NAMESPACE, "GetCustomerByIdPwdResponse", new GetCustomerByIdPwdResponse().getClass());

        new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... params) {
                HttpTransportSE httpTransport = new HttpTransportSE("URL");
                httpTransport.debug = true;

                try {
                    httpTransport.call(URL, envelope);
                    Log.d("SOAP OBJECT SENT",httpTransport.requestDump);
                    Log.d("SOAP OBJECT RESPONSE",httpTransport.responseDump);
                    GetCustomerByIdPwdResponse customerByIdPwd = (GetCustomerByIdPwdResponse)envelope.bodyIn;
                } catch (IOException | XmlPullParserException e) {
                    e.printStackTrace();
                }
                return null;
            }
        }.execute();

And here is the request and response I get, they are all good :

Request :

<?xml version="1.0" encoding="UTF-8"?>
<v:Envelope xmlns:v="http://www.w3.org/2003/05/soap-envelope" xmlns:c="http://www.w3.org/2003/05/soap-encoding" xmlns:d="http://www.w3.org/2001/XMLSchema" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
   <v:Header>
      <n0:To xmlns:n0="http://www.w3.org/2005/08/addressing">To</n0:To>
      <n1:Action xmlns:n1="http://www.w3.org/2005/08/addressing">rexwebservices/IWebShopServices/GetCustomerByIdPwd</n1:Action>
   </v:Header>
   <v:Body>
      <GetCustomerByIdPwd xmlns="rexwebservices" xmlns:ns2="http://schemas.datacontract.org/2004/07/RexWebServices" xmlns:ns3="http://schemas.microsoft.com/2003/10/Serialization/" id="o0" c:root="1">
         <loginMail i:type="d:string">...</loginMail>
         <pwdSHA1 i:type="d:string">...</pwdSHA1>
      </GetCustomerByIdPwd>
   </v:Body>

Response :

<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
   <s:Header>
      <a:Action s:mustUnderstand="1">rexwebservices/IWebShopServices/GetCustomerByIdPwdResponse</a:Action>
   </s:Header>
   <s:Body>
      <GetCustomerByIdPwdResponse xmlns="rexwebservices">
         <GetCustomerByIdPwdResult xmlns:b="http://schemas.datacontract.org/2004/07/RexWebServices" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
            <b:Customer>
               <b:FirstName>...</b:FirstName>
               <b:Id>...</b:Id>
               <b:IsActived>true</b:IsActived>
               <b:IsLockedOut>false</b:IsLockedOut>
               <b:IsNewsLetterAccepted>false</b:IsNewsLetterAccepted>
               <b:LandLinePhone />
               <b:LastName>...</b:LastName>
               <b:LoginMail>...</b:LoginMail>
               <b:MobilePhone />
               <b:Title>Mr</b:Title>
            </b:Customer>
            <b:ErrorMessage>+00X00000</b:ErrorMessage>
            <b:SessionId>SID</b:SessionId>
         </GetCustomerByIdPwdResult>
      </GetCustomerByIdPwdResponse>
   </s:Body>
</s:Envelope>

And here is the error I get when trying to create my POJO :

11-18 11:36:57.967: E/AndroidRuntime(19208): Caused by: java.lang.ClassCastException: org.ksoap2.serialization.SoapObject cannot be cast to com.example.ksoaptest.GetCustomerByIdPwdResponse
11-18 11:36:57.967: E/AndroidRuntime(19208):    at com.example.ksoaptest.MainActivity$2.doInBackground(MainActivity.java:70)
11-18 11:36:57.967: E/AndroidRuntime(19208):    at com.example.ksoaptest.MainActivity$2.doInBackground(MainActivity.java:1)
11-18 11:36:57.967: E/AndroidRuntime(19208):    at android.os.AsyncTask$2.call(AsyncTask.java:288)
11-18 11:36:57.967: E/AndroidRuntime(19208):    at java.util.concurrent.FutureTask.run(FutureTask.java:237)
11-18 11:36:57.967: E/AndroidRuntime(19208):    ... 4 more

Any help would be great since it's the last step to get me going towards my web service implementation.

Thanks !

UPDATE :

Here is my class for my customer. I now have an error when trying to map the customer to my RexUser class. I added the envelope.addMapping("rexwebservices","RexUser",RexUser.class); mapping to my envelope. I have an Caused by: java.lang.RuntimeException: Unknown Property: FirstName error when it comes to saving the customer data into the user object.

public class RexUser implements KvmSerializable{

    public static final int FIRSTNAME = 0;
    public static final int ID = 1;
    public static final int LASTNAME = 6;
    public static final int LOGINMAIL = 7;
    public static final int MOBILEPHONE = 8;
    public static final int LANDLINEPHONE = 5;
    public static final int TITLE = 9;
    public static final int IS_ACTIVATED = 2;
    public static final int IS_LOCKED_OUT = 3;
    public static final int IS_NEWSLETTER_ACCEPTED = 4;


    String FirstName;
    long Id;
    boolean IsActived;
    boolean IsLockedOut;
    boolean IsNewsLetterAccepted;
    String LandLinePhone;
    String LastName;
    String LoginMail;
    String MobilePhone;
    String Title;

    public RexUser(String firstName, long id, boolean isActivated,
            boolean isLockedOut, boolean isNewsLetterAccepted,
            String landLinePhone, String lastName, String loginMail,
            String mobilePhone, String title) {
        super();
        this.FirstName = firstName;
        this.Id = id;
        this.IsActived = isActivated;
        this.IsLockedOut = isLockedOut;
        this.IsNewsLetterAccepted = isNewsLetterAccepted;
        this.LandLinePhone = landLinePhone;
        this.LastName = lastName;
        this.LoginMail = loginMail;
        this.MobilePhone = mobilePhone;
        this.Title = title;
    }

    public RexUser() {
        // TODO Auto-generated constructor stub
    }

    @Override
    public String toString() {
        HashMap<String,Object> desc = new HashMap<String,Object>();
        desc.put("First name",FirstName);
        desc.put("ID",Id);
        desc.put("is Actived", IsActived);
        desc.put("is Locked Out",IsLockedOut);
        desc.put("isNewsLetterAccepted", IsNewsLetterAccepted);
        desc.put("Land Line Phone", LandLinePhone);
        desc.put("lastname", LastName);
        desc.put("login Mail", LoginMail);
        desc.put("mobile phone",MobilePhone);
        desc.put("title", Title);
        return desc.toString();
    }

    @Override
    public Object getProperty(int arg0) {
        switch(arg0){
        case 0:
            return FirstName;
        case 1:
            return Id;
        case 2:
            return IsActived;
        case 3:
            return IsLockedOut;
        case 4:
            return IsNewsLetterAccepted;
        case 5:
            return LandLinePhone;
        case 6:
            return LastName;
        case 7:
            return LoginMail;
        case 8:
            return MobilePhone;
        case 9:
            return Title;
        default:
            return null;
        }
    }

    @Override
    public int getPropertyCount() {
        return 10;
    }

    @Override
    public void getPropertyInfo(int arg0, Hashtable arg1, PropertyInfo arg2) {
        switch(arg0){
        case 0: 
            arg2.name = "First Name"; 
            arg2.type = String.class; 
            break;
        case 1: 
            arg2.name = "ID"; 
            arg2.type = int.class; 
            break;
        case 2: 
            arg2.name = "Is Actived"; 
            arg2.type = boolean.class; 
            break;
        case 3: 
            arg2.name = "Is Locked Out"; 
            arg2.type = boolean.class; 
            break;
        case 4: 
            arg2.name = "Is Newsletter Accepted"; 
            arg2.type = boolean.class; 
            break;
        case 5: 
            arg2.name = "Landline Phone"; 
            arg2.type = String.class; break;
        case 6: 
            arg2.name = "Last Name"; 
            arg2.type = String.class; 
            break;
        case 7: 
            arg2.name = "Login mail"; 
            arg2.type = String.class; 
            break;
        case 8: 
            arg2.name = "Mobile Phone"; 
            arg2.type = String.class; 
            break;
        case 9: 
            arg2.name = "Title"; 
            arg2.type = String.class; 
            break;
        default:
            break;
        }

    }

    @Override
    public void setProperty(int arg0, Object arg1) {
        switch(arg0){
        case 0:
            FirstName = (String)arg1;
            break;
        case 1:
            Id = (int)arg1;
            break;
        case 2:
            IsActived = (boolean)arg1;
            break;
        case 3:
            IsLockedOut = (boolean)arg1;
            break;
        case 4:
            IsNewsLetterAccepted = (boolean)arg1;
            break;
        case 5:
            LandLinePhone = (String)arg1;
            break;
        case 6:
            LastName = (String)arg1;
            break;
        case 7:
            LoginMail = (String)arg1;
            break;
        case 8:
            MobilePhone = (String)arg1;
            break;
        case 9:
            Title = (String)arg1;
            break;
        default:
            break;
        }

    }
}
1

There are 1 answers

3
mmprog On BEST ANSWER

First make sure that namespace for most outer object in Your structure (GetCustomerByIdPwdResponse) is "rexwebservices", so adding mapping will be sth. like that:

envelope.addMapping("rexwebservices", "GetCustomerByIdPwdResponse", GetCustomerByIdPwdResponse.class);
envelope.addMapping("rexwebservices", "GetCustomerByIdPwdResult", GetCustomerByIdPwdResult.class);

Second thing - class that You defined is only outer box of Your response. I tried to define serializable of response and first level of Your structure. The response You included was correctly parsed to them.

public class GetCustomerByIdPwdResponse implements KvmSerializable {
    GetCustomerByIdPwdResult getCustomerByIdPwdResult;

        @Override
        public Object getProperty(int arg0) {
            if(arg0==0){
                return getCustomerByIdPwdResult;
            }
            return null;
        }

        @Override
        public int getPropertyCount() {
            return 1;
        }

        @Override
        public void getPropertyInfo(int arg0, Hashtable arg1, PropertyInfo arg2) {
            if(arg0==0){
                arg2.name="GetCustomerByIdPwdResult";
                arg2.type=GetCustomerByIdPwdResult.class;
            }
        }

        @Override
        public void setProperty(int arg0, Object arg1) {
            if(arg0==0){
                getCustomerByIdPwdResult=(GetCustomerByIdPwdResult)arg1;
            }
        }
}

public class GetCustomerByIdPwdResult implements KvmSerializable {
    SoapObject Customer; //here goes Customer class ofcourse
    String ErrorMessage;
    String SessionId;

    @Override
    public Object getProperty(int arg0) {
        switch(arg0){
        case 0: return Customer;
        case 1: return ErrorMessage;
        case 2: return SessionId;
        }
        return null;
    }

    @Override
    public int getPropertyCount() {
        return 3;
    }

    @Override
    public void getPropertyInfo(int arg0, Hashtable arg1, PropertyInfo arg2) {
        switch(arg0){
        case 0: arg2.name="Customer"; arg2.type=SoapObject.class;break; //Customer class
        case 1: arg2.name="ErrorMessage"; arg2.type=PropertyInfo.STRING_CLASS;break;
        case 2: arg2.name="SessionId"; arg2.type=PropertyInfo.STRING_CLASS;break;
        }
    }

    @Override
    public void setProperty(int arg0, Object arg1) {
        switch(arg0){
        case 0: Customer=(SoapObject)arg1;break;//Customer class
        case 1: ErrorMessage=(String)arg1;break;
        case 2: SessionId=(String)arg1;break;
        }
    }
}

I left Customer class for You - that is why Customer field in GetCustomerByIdPwdResult class is declared as SoapObject.

Hope it will help. Marcin