0

0

Android Ksoap2序列化嵌套整数数组到.NET Web服务的解决方案

碧海醫心

碧海醫心

发布时间:2025-10-23 11:44:24

|

289人浏览过

|

来源于php中文网

原创

android ksoap2序列化嵌套整数数组到.net web服务的解决方案

本教程旨在解决Android Ksoap2在向.NET Web服务发送包含嵌套整数数组(如`ArrayList`)的自定义对象时遇到的序列化错误。核心解决方案包括将`ArrayList`替换为`Vector`,并为`Vector.class`添加显式Ksoap2类型映射,确保数据正确传输。

在Android开发中,使用Ksoap2库与SOAP协议的Web服务进行交互是常见的需求。然而,当需要发送包含复杂数据类型(尤其是集合类型,如整数数组)的自定义对象到.NET Web服务时,开发者可能会遇到序列化失败的运行时错误,例如java.lang.RuntimeException: Cannot serialize [...]。本文将深入探讨这一问题,并提供一个经过验证的解决方案。

问题描述与初步分析

假设我们有一个自定义的KvmSerializable对象,其中包含一个整数列表,例如ArrayList,并尝试将其发送到.NET Web服务。Web服务的XML结构可能如下所示:


  int
  
    int
    int
  
  string

在Ksoap2的KvmSerializable实现中,我们可能会这样定义filesList:

public class DownloadSelectionInfo implements KvmSerializable {
    // ... 其他属性
    private ArrayList filesList;
    // ... 构造函数、getter/setter

    @Override
    public Object getProperty(int index) {
        // ... 其他属性处理
        switch (index) {
            case 1: // 假设filesList是第二个属性
                return filesList;
            // ...
        }
        return null;
    }

    @Override
    public int getPropertyCount() {
        return 3; // 示例:Token, Type, DownloadSelectionInfo
    }

    @Override
    public void getPropertyInfo(int index, Hashtable arg1, PropertyInfo info) {
        // ... 其他属性处理
        switch (index) {
            case 1:
                info.type = PropertyInfo.VECTOR_CLASS; // 尝试使用VECTOR_CLASS
                info.name = "filesList";
                break;
            // ...
        }
    }

    @Override
    public void setProperty(int index, Object value) {
        // ... 其他属性处理
        switch (index) {
            case 1:
                // Ksoap2在反序列化时,会为集合中的每个元素调用setProperty
                // 因此这里需要将value添加到列表中
                if (filesList == null) {
                    filesList = new ArrayList<>();
                }
                filesList.add(Integer.parseInt(value.toString()));
                break;
            // ...
        }
    }
}

在调用Web服务时,我们可能会这样构建SoapObject:

// 构建filesList的SoapObject
SoapObject soFilesList = new SoapObject(Util.getWebService(), "filesList");
for (Integer i : downloadSelectionInfo.getFilesList()) {
    soFilesList.addProperty("int", i); // 为每个整数添加一个名为"int"的属性
}
soDownloadSelectionInfo.addSoapObject(soFilesList); // 将集合SoapObject添加到父对象

// ... 为DownloadSelectionInfo添加PropertyInfo
PropertyInfo pi = new PropertyInfo();
pi.setName("DownloadSelectionInfo");
pi.setValue(downloadSelectionInfo);
pi.setType(DownloadSelectionInfo.class);
request.addProperty(pi);

// 注册自定义类型映射
soapEnvelope.addMapping(Util.getWebService(), "DownloadSelectionInfo", DownloadSelectionInfo.class);

尽管我们尝试在getPropertyInfo中将filesList的类型设置为PropertyInfo.VECTOR_CLASS,并且正确地构建了SoapObject,但运行时仍然可能抛出RuntimeException: Cannot serialize [10,9,1]这样的错误。这表明Ksoap2在内部处理ArrayList作为复杂对象属性时存在兼容性问题,尤其是在与.NET Web服务交互时。

Ksoap2集合类型序列化机制

Ksoap2在处理集合类型时,尤其是在向Web服务发送数据时,对Java集合的具体实现类有特定的偏好。ArrayList虽然是Java中最常用的列表实现,但在某些Ksoap2版本和特定Web服务(如.NET)的组合下,其默认序列化行为可能不符合预期。Ksoap2通常对Vector类有更好的内置支持,因为它在Java的早期版本中被广泛用于表示可序列化的动态数组,并且其内部结构与Ksoap2期望的某些序列化模式更为吻合。

当Ksoap2尝试序列化一个KvmSerializable对象中的ArrayList属性时,如果没有显式的、兼容的类型映射,它可能无法正确识别并处理其内部元素,从而导致序列化失败。

解决方案详解

解决此问题的关键在于两点:将ArrayList替换为Vector,并为Vector.class添加显式的Ksoap2类型映射。

1. 使用 Vector 替换 ArrayList

将DownloadSelectionInfo类中的ArrayList改为Vector。Vector是一个线程安全的动态数组,它实现了List接口,并且在Ksoap2的内部处理中通常具有更好的兼容性。

import java.util.Vector; // 导入Vector

public class DownloadSelectionInfo implements KvmSerializable {
    // ...
    private Vector filesList; // 将ArrayList改为Vector
    // ...
}

2. 更新 KvmSerializable 实现

相应地,getProperty、getPropertyInfo和setProperty方法也需要适配Vector。虽然Vector和ArrayList在方法签名上相似,但关键在于getPropertyInfo中类型声明的准确性。

AI发型设计
AI发型设计

虚拟发型试穿工具和发型模拟器

下载
public class DownloadSelectionInfo implements KvmSerializable {
    // ...
    private Vector filesList; // 已更改为Vector

    // ... 构造函数、getter/setter

    @Override
    public Object getProperty(int index) {
        // ...
        switch (index) {
            case 1:
                return filesList;
            // ...
        }
        return null;
    }

    @Override
    public int getPropertyCount() {
        return 3; // 示例:Token, Type, DownloadSelectionInfo
    }

    @Override
    public void getPropertyInfo(int index, Hashtable arg1, PropertyInfo info) {
        // ...
        switch (index) {
            case 1:
                info.type = PropertyInfo.VECTOR_CLASS; // 确保类型为VECTOR_CLASS
                info.name = "filesList";
                break;
            // ...
        }
    }

    @Override
    public void setProperty(int index, Object value) {
        // ...
        switch (index) {
            case 1:
                if (filesList == null) {
                    filesList = new Vector<>(); // 初始化为Vector
                }
                // Ksoap2在反序列化时,会为集合中的每个元素调用setProperty
                // 因此这里需要将value添加到列表中
                filesList.add(Integer.parseInt(value.toString()));
                break;
            // ...
        }
    }
}

3. 添加 Vector 类型的显式映射

这是解决问题的关键一步。即使在getPropertyInfo中声明了VECTOR_CLASS,Ksoap2也可能需要一个全局的类型映射来正确识别和处理Vector对象。我们需要在SoapEnvelope中为Vector.class添加一个显式映射。

// ... 在构建SoapEnvelope之后,但在执行请求之前
// 注册自定义类型映射
soapEnvelope.addMapping(Util.getWebService(), "DownloadSelectionInfo", DownloadSelectionInfo.class);

// 关键:为filesList的实际类型(Vector)添加映射
soapEnvelope.addMapping(Util.getWebService(), "filesList", Vector.class); // 这里的"filesList"是XML中的元素名

这里的"filesList"应与XML中表示集合的元素名称相匹配。如果Web服务期望的是一个通用的数组类型,有时可能需要映射到Array.class或SoapObject.class,但对于嵌套在自定义对象中的Vector,直接映射Vector.class通常是有效的。

4. 构建 SoapObject 包含集合

构建SoapObject的部分保持不变,因为它已经正确地为每个整数添加了名为"int"的属性,符合XML结构。

// 构建filesList的SoapObject
SoapObject soFilesList = new SoapObject(Util.getWebService(), "filesList");
for (Integer i : downloadSelectionInfo.getFilesList()) { // getFilesList()现在返回Vector
    soFilesList.addProperty("int", i);
}
soDownloadSelectionInfo.addSoapObject(soFilesList);

完整示例代码

结合上述所有更改,以下是修正后的DownloadSelectionInfo类和Web服务调用代码片段:

DownloadSelectionInfo 类:

import org.ksoap2.serialization.KvmSerializable;
import org.ksoap2.serialization.PropertyInfo;
import org.ksoap2.serialization.SoapObject;

import java.util.Hashtable;
import java.util.Vector; // 导入Vector

public class DownloadSelectionInfo implements KvmSerializable {

    private String token;
    private String type;
    private Vector filesList; // 更改为Vector
    private String filename;

    // 默认构造函数
    public DownloadSelectionInfo() {
        this.filesList = new Vector<>();
    }

    // 带参数的构造函数(可选)
    public DownloadSelectionInfo(String token, String type, Vector filesList, String filename) {
        this.token = token;
        this.type = type;
        this.filesList = filesList;
        this.filename = filename;
    }

    // Getter和Setter方法
    public String getToken() { return token; }
    public void setToken(String token) { this.token = token; }
    public String getType() { return type; }
    public void setType(String type) { this.type = type; }
    public Vector getFilesList() { return filesList; }
    public void setFilesList(Vector filesList) { this.filesList = filesList; }
    public String getFilename() { return filename; }
    public void setFilename(String filename) { this.filename = filename; }

    @Override
    public Object getProperty(int index) {
        switch (index) {
            case 0: return token;
            case 1: return type;
            case 2: return filesList; // 返回Vector对象
            case 3: return filename;
        }
        return null;
    }

    @Override
    public int getPropertyCount() {
        return 4; // token, type, filesList, filename
    }

    @Override
    public void getPropertyInfo(int index, Hashtable arg1, PropertyInfo info) {
        switch (index) {
            case 0:
                info.type = PropertyInfo.STRING_CLASS;
                info.name = "Token";
                break;
            case 1:
                info.type = PropertyInfo.STRING_CLASS;
                info.name = "Type";
                break;
            case 2:
                info.type = PropertyInfo.VECTOR_CLASS; // 声明为VECTOR_CLASS
                info.name = "filesList";
                break;
            case 3:
                info.type = PropertyInfo.STRING_CLASS;
                info.name = "Filename";
                break;
            default:
                break;
        }
    }

    @Override
    public void setProperty(int index, Object value) {
        switch (index) {
            case 0:
                token = value.toString();
                break;
            case 1:
                type = value.toString();
                break;
            case 2:
                // Ksoap2在反序列化时,会为集合中的每个元素调用setProperty
                // 因此这里需要将value添加到列表中
                if (filesList == null) {
                    filesList = new Vector<>();
                }
                filesList.add(Integer.parseInt(value.toString()));
                break;
            case 3:
                filename = value.toString();
                break;
            default:
                break;
        }
    }
}

Web服务调用代码片段:

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

import java.util.Vector; // 导入Vector

public class WebServiceCaller {

    // 假设Util.getWebService()返回Web服务的命名空间
    // 假设Util.getWebServiceGed()返回Web服务的命名空间 (根据原答案修正,可能是一个特定的命名空间)
    private static final String NAMESPACE = Util.getWebService();
    private static final String URL = "YOUR_WEB_SERVICE_URL"; // 替换为实际URL
    private static final String SOAP_ACTION = NAMESPACE + "YOUR_METHOD_NAME"; // 替换为实际SOAP Action

    public void callWebService(DownloadSelectionInfo downloadSelectionInfo) {
        SoapObject request = new SoapObject(NAMESPACE, "YourMethodName"); // 替换为实际方法名

        // 为DownloadSelectionInfo构建SoapObject (如果DownloadSelectionInfo本身是方法的参数)
        SoapObject soDownloadSelectionInfo = new SoapObject(NAMESPACE, "DownloadSelectionInfo");

        // 添加Token和Type属性
        soDownloadSelectionInfo.addProperty("Token", downloadSelectionInfo.getToken());
        soDownloadSelectionInfo.addProperty("Type", downloadSelectionInfo.getType());

        // 添加filesList
        SoapObject soFilesList = new SoapObject(NAMESPACE, "filesList"); // XML中的filesList元素名
        for (Integer i : downloadSelectionInfo.getFilesList()) {
            soFilesList.addProperty("int", i); // XML中的元素
        }
        soDownloadSelectionInfo.addSoapObject(soFilesList);

        // 添加Filename属性
        soDownloadSelectionInfo.addProperty("Filename", downloadSelectionInfo.getFilename());


        // 将构建好的DownloadSelectionInfo SoapObject作为参数添加到请求中
        PropertyInfo piDownloadSelectionInfo = new PropertyInfo();
        piDownloadSelectionInfo.setName("DownloadSelectionInfo"); // 参数名
        piDownloadSelectionInfo.setValue(soDownloadSelectionInfo); // 值是一个SoapObject
        piDownloadSelectionInfo.setType(soDownloadSelectionInfo.getClass()); // 类型是SoapObject
        request.addProperty(piDownloadSelectionInfo);

        // 或者,如果DownloadSelectionInfo直接作为方法参数,并且是KvmSerializable
        // PropertyInfo pi = new PropertyInfo();
        // pi.setName("DownloadSelectionInfo"); // 参数名
        // pi.setValue(downloadSelectionInfo); // 值是KvmSerializable对象
        // pi.setType(DownloadSelectionInfo.class); // 类型是KvmSerializable类
        // request.addProperty(pi);


        SoapSerializationEnvelope soapEnvelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
        soapEnvelope.dotNet = true; // 针对.NET Web服务设置
        soapEnvelope.setOutputSoapObject(request);

        // 注册自定义类型映射
        soapEnvelope.addMapping(NAMESPACE, "DownloadSelectionInfo", DownloadSelectionInfo.class);
        // 关键:为filesList的实际类型(Vector)添加映射
        // 根据原答案,这里可能需要使用另一个命名空间,例如 Util.getWebServiceGed()
        soapEnvelope.addMapping(Util.getWebServiceGed(), "filesList", Vector.class);


        HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
        try {
            androidHttpTransport.call(SOAP_ACTION, soapEnvelope);
            // 处理响应
            SoapObject result = (SoapObject) soapEnvelope.getResponse();
            // ...
        } catch (Exception e) {
            e.printStackTrace();
            // 错误处理
        }
    }
}

注意:在soapEnvelope.addMapping(Util.getWebServiceGed(), "filesList", Vector.class);这一行中,Util.getWebServiceGed()是根据原始解决方案提供的,可能代表Web服务中用于filesList元素的特定命名空间,或者是一个通用的命名空间。在实际应用中,您需要根据Web服务的WSDL文件确认正确的命名空间。

总结与最佳实践

当使用Android Ksoap2与.NET Web服务进行复杂数据类型(特别是包含集合的自定义对象)交互时,请遵循以下最佳实践:

  1. 优先使用 Vector 替代 ArrayList: 在KvmSerializable实现中,对于列表或数组类型的属性,Vector通常比ArrayList具有更好的Ksoap2兼容性。
  2. 准确声明 PropertyInfo.type: 在getPropertyInfo方法中,确保为Vector类型的属性设置info.type = PropertyInfo.VECTOR_CLASS。
  3. 添加显式类型映射: 这是最关键的一步。除了为自定义KvmSerializable类添加映射外,务必为Vector.class也添加一个显式的soapEnvelope.addMapping(),并确保命名空间和元素名与Web服务WSDL定义相符。
  4. .NET兼容性设置: 对于.NET Web服务,务必设置soapEnvelope.dotNet = true;。
  5. WSDL分析: 仔细分析Web服务的WSDL文件,了解其期望的XML结构、元素名称和命名空间,这对于正确构建SoapObject和添加类型映射至关重要。

通过遵循这些步骤,您可以有效地解决Ksoap2在序列化嵌套集合到.NET Web服务时遇到的运行时错误,确保数据传输的顺利进行。

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

831

2023.06.15

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

737

2023.07.05

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

733

2023.07.31

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

397

2023.08.01

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

398

2023.08.02

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

446

2023.08.02

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

430

2023.08.02

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

16925

2023.08.03

Java 项目构建与依赖管理(Maven / Gradle)
Java 项目构建与依赖管理(Maven / Gradle)

本专题系统讲解 Java 项目构建与依赖管理的完整体系,重点覆盖 Maven 与 Gradle 的核心概念、项目生命周期、依赖冲突解决、多模块项目管理、构建加速与版本发布规范。通过真实项目结构示例,帮助学习者掌握 从零搭建、维护到发布 Java 工程的标准化流程,提升在实际团队开发中的工程能力与协作效率。

10

2026.01.12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 2.4万人学习

C# 教程
C# 教程

共94课时 | 6.5万人学习

Java 教程
Java 教程

共578课时 | 45.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号