如何基于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:
- 用IDE(比如IntelliJ/Eclipse)的内置功能:打开你的SOAP XML文件,右键选择「Generate → XML Schema」,自动生成对应的XSD。
- 运行
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完成反序列化,步骤很简单:
- 创建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);
- 用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
相关产品推荐
相关产品推荐

