如何在 Java Web 服务客户端中更改编组输出

How to make changes in marshalled output in Java web service client

我正在尝试与第三方 Web 服务交互,该服务要求我在每个请求中发送安全令牌。令牌本身就是一个节点,我从初始调用的响应中获取它。 Web 服务端点是 dotNet,我有一个 Java 客户端。

显然,服务器端希望我发送的安全令牌与提供给我的完全一样:完全相同的字符串:所以如果其内容具有不同的大小、顺序等,它就不会这样做。

因此,在 SoapUI 中,一切正常。初始 'startSession' 调用的响应中有一个标记,我将其复制到下一个调用的请求中。

但是在 Java 中(我尝试了 JAX-WS 和 CXF 生成的代码,它们都依赖于 JAXB)它不起作用。在解组后,我将令牌作为对象接收,并在下一次调用中使用该对象。 编组和发送时,它在子节点中缺少名称空间属性。服务器端说它不会继续,因为令牌不正确。 因此,通过使用 JAXB 出站逻辑处理程序功能,我能够在 DOM 源中毫无问题地添加缺少的名称空间(我也能够使用 CXF 拦截器实现此目的)。

现在的问题是,属性在编组时的排序方式导致结果仍然与提供的标记不匹配,因为它在未编组之前是这样的。尽管这无关紧要,但这些属性的顺序很重要。

我不知道如何解决这个问题,除非可以实际修改输出 XML 字符串。我什至通过从子节点中删除所有属性并用一个视觉上看起来相同的属性替换它们来尝试一种肮脏的黑客攻击;但是外面的两个双引号变成了单引号...

我希望任何人都有想法。因为我有none。

干杯。

更新: 我应该提到有问题的属性是 namespace(d) 属性。该节点应如下所示:

<HawanedoSessionInfo xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.thecompany.com/Hawanedo/Business/v2.0c">

但是,在使用出站 JAXB 处理程序添加缺少的 xmlns="..." 后,我的结果如下所示:

<HawanedoSessionInfo xmlns="http://schemas.thecompany.com/Hawanedo/Business/v2.0c" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

在 HawanedoSessionInfo class 中,我使用了 XmlType.proporder 和 @XmlAttribute,如下所示:

@XmlType(name = "HawanedoSessionInfo", propOrder = {
"xsd",
"xsi",
"xmlns", 

和其他一些非属性子元素..

    private String xsd;
private String xsi;
private String xmlns;

    @XmlAttribute(ns="http://schemas.thecompany.com/Hawanedo/Business/v2.0c")
public String getXsd() {
    return xsd;
}

public void setXsd(final String xsd) {

    this.xsd = xsd;
}

@XmlAttribute(ns="http://schemas.thecompany.com/Hawanedo/Business/v2.0c")
public String getXsi() {
    return xsi;
}

public void setXsi(final String xsi) {

    this.xsi = xsi;
}

@XmlAttribute
public String getXmlns() {
    return xmlns;
}

public void setXmlns(final String xmlns) {

    this.xmlns = xmlns;
}

显然proporder 选项在这种情况下没有帮助?

更新 2:

就像我在回答中写的那样,它现在可以工作了。基于此LINK, 在 HawanedoSessionInfo class 我添加了:

@XmlCustomizer(HawanedoSessionInfoCustomizer.class)

我完全按照链接页面中的描述创建了定制器 class,并添加了 jaxb.properties。

所以我做了两件事:

1) 我将我的属性添加到(已存在的顶部)propOrder 属性。我将属性添加为实例变量并创建了 getters/setters。我用 XmlAttribute 注释了 getter。

2) 我实施了 XmlCustomizer 解决方案。

奇怪的部分来了。按照Fiddler的说法,属性的顺序还是没变!但我必须强调,只有在实施 Customizer 之后,这才有效。这里发生了什么? :)

您可以使用

来控制顺序
@XmlType (propOrder={"prop1","prop2",..."propN"})

所以原则上您不能以标准方式控制属性的顺序,但是....

  1. 根据 jaxb/java 版本,顺序可以通过名称的字母顺序、声明顺序来确定。 如果 a) 移动字段会改变任何内容,b) 重命名字段(XMLAttribute 而不是必须映射到原始名称),您可以在代码中尝试。

如果你运气好,它会起作用。但当然这是一个 hack 并且会在下一个 jaxb/java 更新之前工作。

  1. JAXB 提供程序(实际实现可以具有额外的功能),可用于自定义编组过程)。例如,我发现:https://community.oracle.com/thread/977397 abut eclipselink.

  2. 我确信有一种方法可以在发送之前拦截 soap 主体,或者在发送之前管理数据序列化。我可以想到它是如何调用的,但尝试 google jaxws 客户端自定义。如果您捕获整个 soap 消息,简单的 xslt 转换可以修复属性顺序。

我感受到你的痛苦。使用 xml、jaxws 等的全部目的是让我们的生活更轻松,然后某些供应商决定不遵循标准,你最终会得到一个你试图清理几天的烂摊子。祝你好运,也许可以尝试联系来自 Eclipse Moxy

的 xml 专家

我现在很高兴,因为我让它工作了,而且只花了我整整一周的时间...:) 在@Zielu 的帮助下,有人指出我 link Blaise Doughan 建议的 EclipseLink XMLCustomizer 解决方案:XMLCustomizer solution

我使用了我原来问题中的代码('UPDATE' 下方)并按照建议添加了确切的解决方案。不确定这是否是必要的,但它确实有效。谢谢大家。