You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于SOAP XML响应生成Java POJO并实现XML反序列化

嘿,我完全懂你现在的头疼点——SOAP响应的POJO生成确实比请求类麻烦不少,尤其是碰到带命名空间和嵌套结构的XML时,谷歌搜不到精准方案也正常。别慌,我给你两种实用方案,自动生成省时间,手动编写更灵活,再附上反序列化的具体实现,一步步来解决:

方法一:自动生成POJO(最快最省心的首选)

既然是SOAP API,优先用WSDL生成所有类,这是最靠谱的方式,因为WSDL里已经定义了所有请求响应的结构细节。

如果能拿到API的WSDL地址(一般是http://xxx.xxx/your-service?wsdl),直接用JDK自带的wsimport命令生成:

wsimport -keep -verbose http://your-api-url?wsdl
  • -keep参数会保留生成的.java文件(默认只生成.class)
  • -verbose可以看到生成过程的细节
    生成的类会包含SOAP的Envelope、Header、Body,以及业务相关的HotelSearchResponse、HotelResult等所有POJO,命名空间、字段映射都自动处理好了,完全不用手动调整。

如果只有XML响应没有WSDL,那先从XML生成XSD(XML Schema),再用xjc工具生成POJO:

  1. 用IDE(比如IntelliJ/Eclipse)的内置功能:打开你的SOAP XML文件,右键选择「Generate → XML Schema」,自动生成对应的XSD。
  2. 运行xjc命令生成POJO:
xjc your-generated-schema.xsd -p com.your.project.package
  • -p指定生成类的包名,避免类名冲突
方法二:手动编写POJO(适合需要自定义结构的场景)

如果自动生成的类太冗余,或者你想自己控制字段和类结构,那就用JAXB注解手动编写。核心是用@XmlRootElement、@XmlElement、@XmlAttribute等注解映射XML结构,下面是关键类的示例:

1. 核心业务类:HotelSearchResponse

package com.your.package;

import javax.xml.bind.annotation.*;
import java.util.List;

@XmlRootElement(name = "HotelSearchResponse", namespace = "http://TekTravel/HotelBookingApi")
@XmlAccessorType(XmlAccessType.FIELD) // 直接用字段映射,不用getter/setter的注解
public class HotelSearchResponse {

    @XmlElement(name = "Status", namespace = "http://TekTravel/HotelBookingApi")
    private Status status;

    @XmlElement(name = "ResponseTime", namespace = "http://TekTravel/HotelBookingApi")
    private String responseTime;

    @XmlElement(name = "SessionId", namespace = "http://TekTravel/HotelBookingApi")
    private String sessionId;

    @XmlElement(name = "NoOfRoomsRequested", namespace = "http://TekTravel/HotelBookingApi")
    private int noOfRoomsRequested;

    // 省略CheckInDate、CheckOutDate等字段...

    @XmlElementWrapper(name = "RoomGuests", namespace = "http://TekTravel/HotelBookingApi")
    @XmlElement(name = "RoomGuest", namespace = "http://TekTravel/HotelBookingApi")
    private List<RoomGuest> roomGuests;

    @XmlElementWrapper(name = "HotelResultList", namespace = "http://TekTravel/HotelBookingApi")
    @XmlElement(name = "HotelResult", namespace = "http://TekTravel/HotelBookingApi")
    private List<HotelResult> hotelResultList;

    // 所有字段的getter和setter
}

2. 嵌套类:Status

package com.your.package;

import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
public class Status {
    @XmlElement(name = "StatusCode", namespace = "http://TekTravel/HotelBookingApi")
    private String statusCode;

    @XmlElement(name = "Description", namespace = "http://TekTravel/HotelBookingApi")
    private String description;

    // Getter和Setter
}

3. 带属性的类:RoomGuest

XML里的<RoomGuest AdultCount="2" ChildCount="0" />是属性,用@XmlAttribute映射:

package com.your.package;

import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
public class RoomGuest {
    @XmlAttribute(name = "AdultCount")
    private int adultCount;

    @XmlAttribute(name = "ChildCount")
    private int childCount;

    // Getter和Setter
}

4. 日期字段的处理(可选)

如果想把CheckInDate这类字符串转成Date类型,需要自定义适配器:

package com.your.package;

import javax.xml.bind.annotation.adapters.XmlAdapter;
import java.text.SimpleDateFormat;
import java.util.Date;

public class DateAdapter extends XmlAdapter<String, Date> {
    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");

    @Override
    public Date unmarshal(String dateStr) throws Exception {
        return DATE_FORMAT.parse(dateStr);
    }

    @Override
    public String marshal(Date date) throws Exception {
        return DATE_FORMAT.format(date);
    }
}

然后在字段上添加注解:

@XmlElement(name = "CheckInDate", namespace = "http://TekTravel/HotelBookingApi")
@XmlJavaTypeAdapter(DateAdapter.class)
private Date checkInDate;
反序列化SOAP XML到POJO

不管是自动生成还是手动编写的类,都可以用JAXB完成反序列化,步骤很简单:

  1. 创建JAXB上下文(指定根类,比如自动生成的Envelope或者手动写的HotelSearchResponse):
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import java.io.StringReader;

// 如果是处理整个SOAP Envelope
JAXBContext jaxbContext = JAXBContext.newInstance(Envelope.class);
// 如果只需要解析Body里的HotelSearchResponse,也可以直接指定它
// JAXBContext jaxbContext = JAXBContext.newInstance(HotelSearchResponse.class);
  1. 用Unmarshaller解析XML字符串:
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
String soapXml = "你的SOAP响应XML字符串";
StringReader reader = new StringReader(soapXml);

// 解析整个Envelope
Envelope envelope = (Envelope) unmarshaller.unmarshal(reader);
// 获取业务响应
HotelSearchResponse response = envelope.getBody().getHotelSearchResponse();

// 如果直接解析HotelSearchResponse,需要确保XML里只包含该节点(或者用JAXB的过滤)
// HotelSearchResponse response = (HotelSearchResponse) unmarshaller.unmarshal(reader);

注意事项

  • 命名空间必须匹配:所有注解里的namespace要和XML里的完全一致,比如http://TekTravel/HotelBookingApi,否则会导致字段解析为空。
  • JDK版本问题:JDK8及以前自带JAXB,JDK9+需要手动添加依赖(比如jaxb-api、jaxb-impl、jaxb-core)。

内容的提问来源于stack exchange,提问作者mohammad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:48:56