如何在JAX-WS生成的SOAP响应中将自闭合标签转为空标签对?
解决JAX-WS生成自闭合标签的问题
方法1:通过SOAP消息拦截器修改DOM结构
JAX-WS支持自定义消息处理器拦截输出的SOAP消息,直接修改DOM节点避免自闭合标签:
- 实现
SOAPHandler<SOAPMessageContext>接口,在出站消息处理逻辑中遍历SOAP体的所有节点 - 识别出没有子节点的空元素,为其添加一个空文本节点,这样DOM序列化时会生成
<tag></tag>格式而非自闭合标签 - 修改完成后保存SOAP消息的变更
示例代码片段:
public class EmptyTagFixHandler implements SOAPHandler<SOAPMessageContext> { @Override public boolean handleMessage(SOAPMessageContext context) { Boolean isOutbound = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); if (isOutbound) { try { SOAPBody soapBody = context.getMessage().getSOAPBody(); processEmptyElements(soapBody); context.getMessage().saveChanges(); } catch (SOAPException e) { e.printStackTrace(); } } return true; } private void processEmptyElements(Node node) { NodeList childNodes = node.getChildNodes(); for (int i = 0; i < childNodes.getLength(); i++) { Node child = childNodes.item(i); if (child.getNodeType() == Node.ELEMENT_NODE && child.getFirstChild() == null) { child.appendChild(child.getOwnerDocument().createTextNode("")); } processEmptyElements(child); } } // 实现接口剩余方法:getHeaders、handleFault、close }
最后通过@HandlerChain注解或代码注册该处理器到你的服务类中。
方法2:自定义JAXB适配器控制字段序列化
如果空元素是JAXB序列化实体类字段生成的,可通过自定义XmlAdapter强制输出空内容:
- 编写适配器类,当字段值为
null或空字符串时,返回空字符串而非null - 在实体类的对应字段上添加
@XmlJavaTypeAdapter注解绑定适配器
示例代码:
public class EmptyStringAdapter extends XmlAdapter<String, String> { @Override public String unmarshal(String v) throws Exception { return v; } @Override public String marshal(String v) throws Exception { return v == null ? "" : v; } } // 实体类中使用 public class UserInfo { @XmlJavaTypeAdapter(EmptyStringAdapter.class) private String address; // 其他字段及getter/setter }
该方法仅对JAXB负责序列化的字段生效,SOAP框架生成的信封部分需结合方法1处理。
方法3:调整XML序列化输出属性
部分JAX-WS实现(如Metro)允许通过Transformer的输出属性禁用自闭合标签:
- 获取SOAP消息的Transformer实例,设置特定输出属性强制XML1.1格式(部分环境下可避免自闭合标签)
- 将修改后的XML重新加载回SOAP消息
示例代码片段:
SOAPMessage soapMsg = context.getMessage(); ByteArrayOutputStream outStream = new ByteArrayOutputStream(); Transformer transformer = TransformerFactory.newInstance().newTransformer(); transformer.setOutputProperty(OutputKeys.METHOD, "xml"); transformer.setOutputProperty("{http://xml.apache.org/xalan}serializeAsXML11", "true"); Source source = soapMsg.getSOAPPart().getContent(); transformer.transform(source, new StreamResult(outStream)); // 重新加载修改后的XML soapMsg.getSOAPPart().setContent(new StreamSource(new ByteArrayInputStream(outStream.toByteArray()))); soapMsg.saveChanges();
注意:不同JAX-WS厂商的实现可能需要调整属性参数,需结合实际环境测试。
内容的提问来源于stack exchange,提问作者CodeDebugger
相关产品推荐
相关产品推荐

