3

PHP (nuSOAP) で記述された SOAP サービスから複雑なオブジェクトの配列を取得しようとしています。Android-Client を作成し、ksoap2 ライブラリ (3.0.0 RC.4) を使用しようとしています。このオンラインにはいくつかの「解決策」があり、同じ問題に直面していた何人かの人々がいます. そこで、私の意見では、私が得たいものに最も近いコードを紹介します。

まず最初に - SOAP 応答 (ボディ):

<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だったので、問題はマッピング(およびクラス定義のofc)部分で見つかると確信しています:

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」のベクトルがあるため、これは私には不可能です。 like this.add(value); は、引数 (タイプ: オブジェクト) を DataPlusID-vector に入れることができないため、機能しません。

「GetListResponse」クラスの setProperty メソッドを次のように変更して、これを解決しようとしました。

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));
4

2 に答える 2

6

元の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));
        }
    }
}

DataArray:

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();
于 2013-01-11T20:58:03.953 に答える
5

私の知る限り、GetListResponse クラスは Vector を含むのではなく、Vector を拡張する必要があります。書類確認はこちら

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

更新
申し訳ありませんが、複雑なオブジェクトの配列に対してマッピングアプローチを使用したことはありません。を使用して繰り返しループを構築し、そのプロパティを手動で取得する別のアプローチを試すことができます (クラスVector<SoapObject>は必要ありません)。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"));
}

このアプローチはドキュメントにあり、うまくいくはずです。

于 2013-01-09T03:15:27.997 に答える