使用纯 JAX-WS 添加 SOAP 标头对象 [英] Add SOAP header object using pure JAX-WS

查看:39
本文介绍了使用纯 JAX-WS 添加 SOAP 标头对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 JAX WSPayPal Express Checkout API 实现简单的 Web 服务客户端.PayPal Express Checkout API 提供了 WSDL 文件,我可以从该文件中使用 CXF 的 wsdl2java 实用程序生成 Java 类.

I'm trying to implement simple web service client for PayPal Express Checkout API using JAX WS. PayPal Express Checkout API provides WSDL file, from which I was able to generate Java classes using CXF's wsdl2java utility.

出于身份验证的原因,它需要为每个请求添加SOAP Header.这个标题非常简单,应该如下所示:https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_api_ECSOAPAPIBasics#id09C3I0CF0O6

From authentication reasons, it demands adding SOAP Header to each request. This header is quite simple and should look like here: https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_api_ECSOAPAPIBasics#id09C3I0CF0O6

WSDL 类生成,包括 ebay.apis.eblbasecomponents.CustomSecurityHeaderType 类,它表示我需要添加到每个请求的标头.

Generated from WSDL classes include ebay.apis.eblbasecomponents.CustomSecurityHeaderType class which represents header which I need to add to each request.

所以问题是:考虑到以下条件,如何将 CustomSecurityHeaderType 类的手动创建的实例添加到 SOAP 请求的标头中:

So the question is: how can I add manually created instance of CustomSecurityHeaderType class to SOAP request's header taking into account following conditions:

  1. 我不是很想使用 com.sun.* 包中的类,如此处的回答所述:JAX-WS - 添加 SOAP 标头(主要是因为不同 JDK 之间可能存在可移植性问题)
  2. 我不想手动将该对象编组到 嵌套 javax.xml.soap.SOAPElement 实例中,如这里的回答中所述:如何使用 Java JAX 添加 SOAP 标头-WS
  1. I'm not very eager to use classes from com.sun.* package as mentioned in answer here: JAX-WS - Adding SOAP Headers (mainly because of possible portability issues between different JDK's)
  2. I don't want to manually marshal that object into nested javax.xml.soap.SOAPElement instances as mentioned in answer here: How do I add a SOAP Header using Java JAX-WS

推荐答案

所以,看起来我在结合 JAX-WS & 时找到了可能的答案JAXB 来自 SO 的相关答案(如果有这些技术经验的人可以检查以下是否正确,我将不胜感激):

So, it looks like I've found possible answer while combining JAX-WS & JAXB related answers from SO (I would really appreciate if somebody experienced in these technologies can check whether following is correct):

对我来说显而易见的是添加 SOAP 消息处理程序并在其中更改 SOAPMessage 实例的标头:

The obvious thing for me is to add SOAP message handler and alter header of SOAPMessage instance in it:

import javax.xml.ws.Binding;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.handler.Handler;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Marshaller;
import javax.xml.soap.SOAPHeader;
import ebay.api.paypalapi.ObjectFactory; // class generated by wsdl2java

// following class is generated by wsdl2java utility Service class
final PayPalAPIInterfaceService payPalService = new PayPalAPIInterfaceService();
final PayPalAPIAAInterface expressCheckoutPort = payPalService.getPayPalAPIAA();
final Binding binding = ((BindingProvider) expressCheckoutPort).getBinding();
List<Handler> handlersList = new ArrayList<Handler>();

// now, adding instance of Handler to handlersList which should do our job:
// creating header instance
final CustomSecurityHeaderType headerObj = new CustomSecurityHeaderType();
final UserIdPasswordType credentials = new UserIdPasswordType();
credentials.setUsername("username");
credentials.setPassword("password");
credentials.setSignature("signature");
headerObj.setCredentials(credentials);

// bookmark #1 - please read explanation after code
final ObjectFactory objectFactory = new ObjectFactory();
// creating JAXBElement from headerObj
final JAXBElement<CustomSecurityHeaderType> requesterCredentials = objectFactory.createRequesterCredentials(headerObj);

handlersList.add(new SOAPHandler<SOAPMessageContext>() {
    @Override
    public boolean handleMessage(final SOAPMessageContext context) {        
        try {
            // checking whether handled message is outbound one as per Martin Strauss answer
            final Boolean outbound = (Boolean) context.get("javax.xml.ws.handler.message.outbound");
            if (outbound != null && outbound) {
                // obtaining marshaller which should marshal instance to xml
                final Marshaller marshaller = JAXBContext.newInstance(CustomSecurityHeaderType.class).createMarshaller();
                // adding header because otherwise it's null
                final SOAPHeader soapHeader = context.getMessage().getSOAPPart().getEnvelope().addHeader();
                // marshalling instance (appending) to SOAP header's xml node
                marshaller.marshal(requesterCredentials, soapHeader);
            }
        } catch (final Exception e) {
            throw new RuntimeException(e);
        }
        return true;
    }

    // ... default implementations of other methods go here

});

// as per Jean-Bernard Pellerin's comment setting handlerChain list here, after all handlers were added to list
binding.setHandlerChain(handlersList);

书签 #1 的说明:不应封送标头对象本身,而应封送表示该对象的 JAXBElement,否则会出现异常.应该使用从 WSDL 生成的 ObjectFactory 类之一,用于从原始对象创建所需的 JAXBElement 实例.(感谢@skaffman 的回答:没有由 JAXB 生成的 @XmlRootElement)

Explanation of bookmark #1: one should marshal not the header object itself, but JAXBElement representing that object, because otherwise one will get an exception. One should use one of ObjectFactory classes which are generated from WSDL for creating needed JAXBElement instances from original objects. (Thanks @skaffman for answer: No @XmlRootElement generated by JAXB )

这篇关于使用纯 JAX-WS 添加 SOAP 标头对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆