【问题标题】:ksoap2 Receive Array of complex objects via SOAPksoap2 通过 SOAP 接收复杂对象数组
【发布时间】:2013-05-10 22:29:58
【问题描述】:

我正在尝试从用 PHP (nuSOAP) 编写的肥皂服务接收复杂对象的数组。我正在尝试编写一个 Android 客户端并使用 ksoap2 库(3.0.0 RC.4)。 网上有一些“解决方案”,有几个人面临同样的问题 - 无论如何,我尝试了很多不同的方法,但我现在仍然卡住了好几天,所以我决定向你们寻求帮助。因此,我将向您展示我认为最接近我想要获得的代码。

第一件事 - SOAP-Response(主体):

<SOAP-ENV:Body>
    <ns1:GetListResponse xmlns:ns1="http://localhost/games_db/games_db.php">
        <return xsi:type="SOAP-ENC:Array" SOAP-ENC:arrayType="tns:DataPlusID[24]">
            <item xsi:type="tns:DataPlusID">
                <data xsi:type="xsd:string">shitload</data>
                <ID xsi:type="xsd:int">4</ID>
            </item>
            <item xsi:type="tns:DataPlusID">
                <data xsi:type="xsd:string">of</data>
                <ID xsi:type="xsd:int">7</ID>
            </item>
            <item xsi:type="tns:DataPlusID">
                <data xsi:type="xsd:string">imformation</data>
                <ID xsi:type="xsd:int">10</ID>
            </item>
        </return>
    </ns1:GetListResponse>
</SOAP-ENV:Body>

当我没有映射任何东西时,“envelope.bodyIn.toString()”会给我以下信息。

GetListResponse{
    return=[
        DataPlusID{data=shitload; ID=4; },
        DataPlusID{data=of; ID=7; },
        DataPlusID{data=information; ID=10; }
    ];
}

这里是类,总有一天会处理响应...

public class GetListResponse implements KvmSerializable {

    private Vector<DataPlusID> datavector = new Vector<DataPlusID>();

    @Override
    public Object getProperty(int arg0) {
        return this.datavector;
    }

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

    @Override
    public void getPropertyInfo(int index, Hashtable properties, PropertyInfo info) {
        info.name = "return";
        info.type = new Vector<DataPlusID>().getClass();
    }

    @Override
    public void setProperty(int index, Object value) {
        this.datavector = (Vector<DataPlusID>) value;
    }
}

public class DataPlusID implements KvmSerializable
{

    private String data;
    private int ID;


    @Override
    public Object getProperty(int arg0) {
        switch(arg0) {
        case 0:
            return data;
        case 1:
            return ID;
        }

        return null;
    }

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

    @Override
    public void getPropertyInfo(int index, Hashtable arg1, PropertyInfo info) {
        switch(index) {
        case 0:
            info.type = PropertyInfo.STRING_CLASS;
            info.name = "data";
            break;
        case 1:
            info.type = PropertyInfo.INTEGER_CLASS;
            info.name = "ID";
            break;
        default:break;
        }
    }

    @Override
    public void setProperty(int index, Object value) {
        switch(index) {
        case 0:
            data = value.toString();
            break;
        case 1:
            ID = Integer.parseInt(value.toString());
            break;
        default:
            break;
        }
    }
}

这是接收消息的代码

public GetListResponse GetList(String liste) throws Exception{

    SoapObject request = new SoapObject(Namespace, MethodGetList);

    request.addProperty("list", liste);

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

    envelope.addMapping(Namespace, "GetListResponse", new GetListResponse().getClass());
    //envelope.addMapping(Namespace, "return", new Vector<DataPlusID>().getClass());
    envelope.addMapping(Namespace, "item", new DataPlusID().getClass()); //tried also "DataPlusID" instead of "item"

    try {
        HttpTransportSE transport = new HttpTransportSE(URL);
        transport.debug = true;

        transport.call(ActionGetList, envelope);

        Log.d("SOAPEnvelope", "Response: "+transport.responseDump);
    } catch (Exception e){
        Log.d("SOAPEnvelope", "Fehler bei Serverabfrage: "+e.toString());
    }
    //Log.d("SOAPEnvelope", "BodyIn: "+envelope.bodyIn.toString());

    GetListResponse result = new GetListResponse();
    result = (GetListResponse)envelope.bodyIn;

    return result;
}

处理数据:

new Thread(new Runnable() {
    public void run() {  
        try {
            GetListResponse response = new GetListResponse();
            response = GetList("genre");

            //content of datavector is below
            Vector<DataPlusID> datavector = new Vector<DataPlusID>();
            datavector = (Vector<DataPlusID>) response.getProperty(0);

            //EXCEPTION IS THROWN HERE
            String x = (String) datavector.get(0).getProperty(0);

            DataPlusID daten0 = new DataPlusID();
            //WOULD ALSO HAPPEN HERE
            daten0 = (DataPlusID) datavector.get(0);

            String genre1 = (String) daten0.getProperty(0);

        } catch (Exception e) {
            Log.d("SOAPEnvelope", e.toString());
        }
    }
}).start();

这里是“datavector”的内容:

(java.util.Vector)
[DataPlusID{data=Action; ID=4; },
DataPlusID{data=Adventure; ID=7; },
DataPlusID{data=Aufbauspiel; ID=10; },
DataPlusID{data=Beat 'em up; ID=11; }]

抛出以下异常:

java.lang.ClassCastException: org.ksoap2.serialization.SoapObject cannot be cast to com.example.gamesdb_client.DataPlusID

最奇怪的是,在调试时我实际上得到了我想要得到的值。 --> 当我检查表达式“datavector.get(0).getProperty(0)”时,我得到:

(java.lang.String) shitload

所以他实际上是以正确的格式(字符串)查看数据,但是当他尝试将其附加到字符串变量时,他给了我一个 ClassCastException?

无论如何,无论我尝试什么,最终结果都是 CCE,所以我很确定问题可以在映射(以及类定义)部分找到:

1 envelope.addMapping(Namespace, "GetListResponse", new GetListResponse().getClass());
2 envelope.addMapping(Namespace, "item", new DataPlusID().getClass());

如果没有第 1 行,我会得到另一个 CCE,所以我希望映射能够按预期工作。 如果没有第 2 行,没有任何变化,所以我很确定问题出在 DataPlusID 类中。

他只是无法链接这些:

DataPlusID{data=shitload; ID=4; },
DataPlusID{data=of; ID=7; },
DataPlusID{data=information; ID=10; }

到 DataPlusID 类。

所以希望有人可以看看这个并给我一些想法如何解决这个问题。 也许只是一些我不明白的基本东西。 - 让我的假期不被浪费^^ 谢谢。

编辑:重新 R4j

问题是,在示例代码中,他们使用了一个字符串向量(使用 this.add(value.toString() 添加它)。 这对我来说是不可能的,因为我有一个“DataPlusID”向量。像这样的东西。add(value);不会工作,因为 他不能将参数(类型:对象)放入 DataPlusID 向量中。

我尝试通过将“GetListResponse”类的 setProperty-method 更改为:

public void setProperty(int index, Object value) {
    this.datavector = (Vector<DataPlusID>) value;

    for (int i = 0; i < datavector.size(); i++) {
        this.add(datavector.elementAt(i));
    }
}

这样我就可以将向量的单个部分设置到类中。

不幸的是,这只是在该行中抛出了相同的 ClassCastExcepiton:

this.add(datavector.elementAt(i));

【问题讨论】:

    标签: java android ksoap2


    【解决方案1】:

    原始 postet 问题的解决方案。

    感谢 R4j - 您的回答对我帮助很大。

    类定义 - GetListResponse:

    public class GetListResponse implements KvmSerializable {
    
        private Vector<SoapObject> datavector = new Vector<SoapObject>();
        private DataArray dataarray = new DataArray();
    
        @Override
        public Object getProperty(int arg0) {
            //return this.datavector.get(arg0);
            return this.dataarray;
        }
    
        @Override
        public int getPropertyCount() {
            return 1;
        }
    
        @Override
        public void getPropertyInfo(int index, Hashtable properties, PropertyInfo info) {
            info.name = "return";
            info.type = new Vector<DataPlusID>().getClass();
        }
    
        @Override
        public void setProperty(int index, Object value) {
            this.datavector = (Vector<SoapObject>) value;
    
            for(int i = 0; i < datavector.size(); i++) {
                dataarray.setProperty(0, datavector.get(i));
            }
        }
    }
    

    数据数组:

    public class DataArray extends Vector<DataPlusID> implements KvmSerializable {
    
        private static final long serialVersionUID = -1166006770093411055L;
    
        @Override
        public Object getProperty(int index) {
            return this.get(index);
        }    
    
        @Override
        public int getPropertyCount() {
            return this.size();
            //return dataArray.length;
        }
    
        @Override
        public void getPropertyInfo(int index, Hashtable properties, PropertyInfo info) {
            info.name = "item";
            info.type = new DataPlusID().getClass();
        }
    
        @Override
        public void setProperty(int index, Object value) {
            SoapObject soapObject = new SoapObject();
            soapObject = (SoapObject) value;
    
            DataPlusID daten = new DataPlusID();
            daten.setProperty(0, soapObject.getProperty("data"));
            daten.setProperty(1, soapObject.getProperty("ID"));
    
            this.add(daten);
        }
    }
    

    DataPlusID:

    public class DataPlusID implements KvmSerializable
    {
    
        private String data;
        private int ID;
    
        @Override
        public Object getProperty(int arg0) {
    
            switch(arg0)
            {
            case 0:
                return data;
            case 1:
                return ID;
            }        
            return null;
        }
    
        @Override
        public int getPropertyCount() {
            return 2;
        }
    
        @Override
        public void getPropertyInfo(int index, Hashtable arg1, PropertyInfo info) {
            switch(index)
            {
            case 0:
                info.type = PropertyInfo.STRING_CLASS;
                info.name = "data";
                break;
            case 1:
                info.type = PropertyInfo.INTEGER_CLASS;
                info.name = "ID";
                break;
            default:break;
            }
        }
    
        @Override
        public void setProperty(int index, Object value) {
            switch(index)
            {
            case 0:
                data = value.toString();
                break;
            case 1:
                ID = Integer.parseInt(value.toString());
                break;
            default:
                break;
            }
        }
    }
    

    接收数据的代码:

    public GetListResponse GetList(String liste) throws Exception{
    
    SoapObject request = new SoapObject(Namespace, MethodGetList);
    
    request.addProperty("list", liste);
    
        final SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
        envelope.setOutputSoapObject(request);
    
        //this is the only necessary mapping
        envelope.addMapping(Namespace, "GetListResponse", new GetListResponse().getClass());
    
        try {
            HttpTransportSE transport = new HttpTransportSE(URL);
            transport.debug = true;
    
            transport.call(ActionGetList, envelope);
    
        } catch (Exception e){
            Log.d("SOAPEnvelope", "Fehler bei Serverabfrage: "+e.toString());
        }
        GetListResponse result = new GetListResponse();
        result = (GetListResponse) envelope.bodyIn;
    
        return result;
    }
    

    处理数据:

    new Thread(new Runnable() {
        public void run() {  
            try {
                @SuppressWarnings("unchecked")
                GetListResponse response = GetList("genre");
    
                DataArray array = (DataArray) response.getProperty(0);
    
                DataPlusID daten = (DataPlusID) array.getProperty(2);
    
                String x = (String) daten.getProperty(0);
    
                Log.d("SOAPEnvelope", "element 3 = "+x);
                //Log says "element 3 = information"
            } catch (Exception e) {
                Log.d("SOAPEnvelope", e.toString());
            }
        }
    }).start();
    

    【讨论】:

      【解决方案2】:

      据我所知,您的 GetListResponse 类应该扩展 Vector 而不是包含它。检查document here

       public class GetListResponse extends Vector<DataPlusID> 
                                      implements KvmSerializable {
        }
      

      更新
      抱歉,我以前从未尝试过对复杂对象数组使用映射方法。您可以尝试another approach,它使用Vector&lt;SoapObject&gt; 构建一个循环遍历并手动获取其属性(您不需要GetListResponse 类)。像这样的:

      Vector<SoapObject> vectorOfSoapObject = (Vector<SoapObject>)envelop.getResponse();
      for (SoapObject soapObject : vectorOfSoapObject) {
         // put all properties into  DataPlusID  object
         DataPlusID  dataPlusIDObj = new DataPlusID();
         dataPlusIDObj.setData(soapObject.getPropertyAsString("data"));
      }
      

      这种方法在the document 中,它应该可以工作。

      【讨论】:

      • *在原帖中回答,评论区太小了,无法正确解释。
      • @Rj4 非常感谢!我现在使用 SoapObject 来设置我的“DataPlusID”类的对象。然后这些对象用于处理数据。 Ofc SoapObject 可以直接读取,但我会保留所有类,因为我认为它们赋予了整个事物更多的结构并使其更加透明。我会将整个代码作为另一个答案发布。
      • 很高兴听到,你也帮了我。我刚刚找到了另一种方法,我会为我的下一个项目尝试它:)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-09-12
      • 2016-02-11
      • 1970-01-01
      • 1970-01-01
      • 2020-12-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多