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

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

问题描述

我正在尝试使用 JAX WS PayPal 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标头.此标头非常简单,应如下所示: 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

包括 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.* 包中的类,如此处答案中所述:如何使用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 &来自 SO JAXB 相关答案(如果对这些技术有经验的人可以检查以下内容是否正确,我将不胜感激):

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天全站免登陆