How to send a SOAP object with FEIGN client? - java

I'm trying to send a SOAP message via a FEIGN client. The problem is that when I send the java object, what is actually being sent is a request with an xml format, instead of a SOAP format.
The client is configured as follows:
#FeignClient(name = "calculatorServer", url = "http://www.dneonline.com/calculator.asmx")
public interface AEMWebServiceFeignClient{
#PostMapping(value = "", consumes = MediaType.TEXT_XML, produces = MediaType.TEXT_XML)
AddResponse calculate(#RequestBody Add addRequest);
}
Looking at the log I see that I am really sending this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Add xmlns="http://tempuri.org/">
<intA>2</intA>
<intB>0</intB>
</Add>
When I really should be sending the following message:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/">
<soapenv:Header/>
<soapenv:Body>
<tem:Add>
<tem:intA>2</tem:intA>
<tem:intB>0</tem:intB>
</tem:Add>
</soapenv:Body>
</soapenv:Envelope>
Any help is welcome, thanks!

You must define a custom Feign codec to use SOAP, as described in here.
To integrate it with FeignClient, you should define a custom configuration class for it, reference.
#FeignClient(
name = "calculatorServer",
url = "http://www.dneonline.com/calculator.asmx"
configuration = MySoapClientConfiguration.class)
public interface AEMWebServiceFeignClient{
#PostMapping(value = "", consumes = MediaType.TEXT_XML, produces = MediaType.TEXT_XML)
AddResponse calculate(#RequestBody Add addRequest);
}
#Configuration
public class MySoapClientConfiguration {
private static final JAXBContextFactory jaxbFactory = new JAXBContextFactory.Builder()
.withMarshallerJAXBEncoding("UTF-8")
.withMarshallerSchemaLocation("http://apihost http://apihost/schema.xsd")
.build();
#Bean
public Encoder feignEncoder() {
return new SOAPEncoder(jaxbFactory);
}
#Bean
public Decoder feignDecoder() {
return new SOAPDecoder(jaxbFactory);
}
}

It's works, but i had added:
Create package-info.java into package addRequest/AddResponse
#XmlSchema(
namespace = "http://tempuri.org/",
elementFormDefault = XmlNsForm.QUALIFIED,
xmlns = {
#XmlNs(prefix = "xsd", namespaceURI = "http://tempuri.org/")
}
)
package your.package.add;
import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
Also, you need to add an interceptor to set content-type and soapAction:
import feign.RequestInterceptor;
import feign.RequestTemplate;
public class FeignRequestSoapInterceptor implements RequestInterceptor {
#Override
public void apply(RequestTemplate requestTemplate) {
requestTemplate.header("Content-Type", "text/xml");
requestTemplate.header("soapAction", "http://tempuri.org/Add");
}
}
In MySoapClientConfiguration, add the FeignRequestSoapInterceptor:
#Configuration
public class MySoapClientConfiguration {
private static final JAXBContextFactory jaxbFactory = new JAXBContextFactory.Builder()
.withMarshallerJAXBEncoding("UTF-8")
.build();
#Bean
public Encoder feignEncoder() {
return new SOAPEncoder(jaxbFactory);
}
#Bean
public Decoder feignDecoder() {
return new SOAPDecoder(jaxbFactory);
}
#Bean
public FeignRequestSoapInterceptor feignRequestSoapInterceptor() {
return new FeignRequestSoapInterceptor();
}
}
FeignClient:
#FeignClient(
name = "calculatorServer",
url = "http://www.dneonline.com/calculator.asmx"
configuration = MySoapClientConfiguration.class)
public interface AEMWebServiceFeignClient{
#PostMapping("/Add")
AddResponse calculate(#RequestBody Add addRequest);
}

Related

Setting soap request security header in Spring Boot application

I am not so familiar with soap service but trying to consume one from a spring boot application. This runs but throws exception as I was not able to set the header as per below soap request.
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:web="http://webservices.service.company.com/">
<soapenv:Header
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:Security>
<wsse:UsernameToken>
<wsse:Username>username</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">Pa$$wrd</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
...
</soapenv:Body>
</soapenv:Envelope>
Here is my configuration classes:
#Configuration
public class SoapClientConfig {
#Bean
public Jaxb2Marshaller marshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath("com.company.ws.wsdl");
return marshaller;
}
#Bean
public SoapClient soapClient(Jaxb2Marshaller marshaller) {
SoapClient client = new SoapClient();
client.setDefaultUri("localhost:8080/service/myservice");
client.setMarshaller(marshaller);
client.setUnmarshaller(marshaller);
return client;
}
}
SoapClient class
#Component
public class SoapClient extends WebServiceGatewaySupport {
public CustSearchResponse getCustomer(CustomerSearchRequest custRequest) {
ObjectFactory objectFactory = new ObjectFactory();
JAXBElement<CustomerSearchRequest> request =
objectFactory.createCustomerSearchRequest(custRequest);
JAXBElement response = (JAXBElement)getWebServiceTemplate().marshalSendAndReceive(
request);
return (CustSearchResponse) response.getValue();
}
}
Looked few examples but it seems so complex and I am not sure how that works with my soap header. Any suggestions would be highly appreciated.
Update
Tried to add securityInterceptor as below
#Bean
public Wss4jSecurityInterceptor securityInterceptor() {
Wss4jSecurityInterceptor security = new Wss4jSecurityInterceptor();
security.setSecurementActions(WSHandlerConstants.TIMESTAMP + " " + WSHandlerConstants.USERNAME_TOKEN);
security.setSecurementPasswordType(WSConstants.PW_TEXT);
security.setSecurementUsername("username");
security.setSecurementPassword("password");
return security;
}
and updated the SoapClient bean as below:
#Bean
public SoapClient soapClient(Jaxb2Marshaller marshaller) {
SoapClient client = new SoapClient();
client.setDefaultUri("localhost:8080/service/myservice");
client.setMarshaller(marshaller);
client.setUnmarshaller(marshaller);
client.setInterceptors(new ClientInterceptor[]{ securityInterceptor() });
return client;
}
Now I am getting below error:
org.springframework.ws.soap.client.SoapFaultClientException: Must Understand check failed for header SOAP-ENV : {http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}Security
at org.springframework.ws.soap.client.core.SoapFaultMessageResolver.resolveFault(SoapFaultMessageResolver.java:38)
at org.springframework.ws.client.core.WebServiceTemplate.handleFault(WebServiceTemplate.java:795)
at org.springframework.ws.client.core.WebServiceTemplate.doSendAndReceive(WebServiceTemplate.java:605)
at org.springframework.ws.client.core.WebServiceTemplate.sendAndReceive(WebServiceTemplate.java:542)
at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:394)
at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:388)
at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:378)

Java WS get SOAP request CDATA body

I need to get the following SOAP request into my controller.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<req:ResultMsg
xmlns:req="http://cps.huawei.com/cpsinterface/result"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<Result>
<ResultType>0</ResultType>
<ResultCode>0</ResultCode>
<ResultDesc>The service request is processed successfully.</ResultDesc>
<OriginatorConversationID>S_X2013012921001</OriginatorConversationID>
<ConversationID>AG_20130129T102103</ConversationID>
<TranactionID>XD2013012923789234</TranactionID>
<ResultParameters></ResultParameters>
</Result>]]></req:ResultMsg>
</soapenv:Body>
</soapenv:Envelope>
I tried to set a POJO and a string for the CDATA part but not working.
Current implementation as below,
Interface:
#WebService(name = "VCashCallbackService",
targetNamespace = "http://cps.huawei.com/cpsinterface/result")
public interface VCashCallbackService {
#WebMethod(operationName = "ResultMsg")
#WebResult(name = "GetDataResponse")
GetDataResponse getData(#WebParam(name = "ResultMsg",
targetNamespace = "http://cps.huawei.com/cpsinterface/resul",
mode = WebParam.Mode.IN) Holder<String> searchResultDataXML);
}
Impl
#WebService(serviceName = "VCashCallbackService",
portName = "VCashCallbackServicePort",
endpointInterface = "com.argon.eightd.web.restful.mock.VCashCallbackService",
targetNamespace = "http://cps.huawei.com/cpsinterface/result")
#BindingType(value = javax.xml.ws.soap.SOAPBinding.SOAP12HTTP_BINDING)
#Service
public class VCashCallbackServiceImpl implements VCashCallbackService {
private static final Logger LOGGER = LoggerFactory.getLogger(VCashCallbackServiceImpl.class);
#Override
public GetDataResponse getData(Holder<String> searchResultDataXML) {
LOGGER.info("SOAP result: {}", searchResultDataXML.searchResultDataXML.value);
return new GetDataResponse();
}
}
Log
SOAP result: null
But this approach is getting the request as above in the WebMethod.
Thanks in advance.

How to Read SOAP API Request Headers Using Java Spring

Below is my soap request, I need to read the soap headers using spring boot java how can I do that.
Tried all possible scenarios I am able to read the headers without the target namespace but if I involve targetnamespace it gives me a null pointer exception error.Thanks for the help in advance.
Actual Requirement Which needs a Solution:
<soap11:Envelope xmlns:soap11="http://schemas.xmlsoap.org/soap/envelope/">
<soap11:Header>
<NS1:CUSTOMERNAME xmlns:NS1="http://www.example.org/EcCustom67ARequest/">XmasTree</NS1:CUSTOMERNAME>
<NS2:EMPID xmlns:NS2="http://www.example.org/EcCustom67ARequest/">kite123</NS2:EMPID>
</soap11:Header>
<soap11:Body>
<clientNS:EcCustom67A xmlns:clientNS="http://www.example.org/EcCustom67ARequest/">
<clientNS:PAYMENT_MODE>NEFT</clientNS:PAYMENT_MODE>
<clientNS:VAN>AUT1123456</clientNS:VAN>
<clientNS:AMOUNT>1000.00</clientNS:AMOUNT>
<clientNS:CREDIT_ACCOUNT_NUMBER>124236541582</clientNS:CREDIT_ACCOUNT_NUMBER>
<clientNS:CUSTOMER_CODE>AUT1</clientNS:CUSTOMER_CODE>
<clientNS:TRANSACTION_DATE>30-04-2021</clientNS:TRANSACTION_DATE>
<clientNS:ADD_INFO>Collection</clientNS:ADD_INFO>
</clientNS:EcCustom67A>
</soap11:Body>
</soap11:Envelope>
Able to do without targetnamespace:
<soapenv:Envelope
xmlns:soapenv = "http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd = "http://www.w3.org/2001/XMLSchema"
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xmlns:ns2 = "http://www.example.org/EcCustom67ARequest/" elementFormDefault="qualified">
<soapenv:Header>
<CUSTOMERNAME>XmasTree</CUSTOMERNAME>
<EMPID>kite123</EMPID>
</soapenv:Header>
<soapenv:Body>
<ns2:EcCustom67A soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" elementFormDefault="qualified">
<ns2:PAYMENT_MODE>NEFT</ns2:PAYMENT_MODE>
<ns2:VAN>ADAN12345678</ns2:VAN>
<ns2:AMOUNT>1000</ns2:AMOUNT>
<ns2:CREDIT_ACCOUNT_NUMBER>108328359093</ns2:CREDIT_ACCOUNT_NUMBER>
<ns2:CUSTOMER_CODE>ADAN</ns2:CUSTOMER_CODE>
<ns2:TRANSACTION_DATE>17-11-2020 13:10:12</ns2:TRANSACTION_DATE>
<ns2:ADD_INFO>Collection</ns2:ADD_INFO>
</ns2:EcCustom67A>
</soapenv:Body>
</soapenv:Envelope>
Working Code :
#Endpoint
public class EcCustom67AEndPoint {
private static final String NAMESPACE_URI = "http://www.example.org/EcCustom67ARequest/";
#PayloadRoot(namespace = NAMESPACE_URI, localPart = "EcCustom67A")
#ResponsePayload
public EcCustom67AResponse getEcCustom67A(#RequestPayload EcCustom67A request,
#SoapHeader(value = "CUSTOMERNAME") SoapHeaderElement customerName,
#SoapHeader(value = "EMPID") SoapHeaderElement empid) throws JAXBException {
EcCustom67AResponse response = new EcCustom67AResponse();
String custName = customerName.getText();
String empID = empid.getText();
response.setAMOUNT(request.getAMOUNT().replaceAll(",", ","));
response.setCREDITACCOUNTNUMBER(request.getCREDITACCOUNTNUMBER());
response.setCUSTOMERCODE(request.getCUSTOMERCODE());
response.setVAN(request.getVAN());
response.setPAYMENTMODE(request.getPAYMENTMODE());
response.setTRANSACTIONDATE(request.getTRANSACTIONDATE());
response.setADDINFO(request.getADDINFO());
if (custName.equals("XmasTree") && empID.equals("kite123")) {
if (response.getAMOUNT() != null) {
if (Float.parseFloat(response.getAMOUNT().replaceAll(",", "")) >= 1000) {
response.setSTATUS("Success");
response.setREMARKS("Beneficiary Account Credited");
} else if (Float.parseFloat(response.getAMOUNT().replaceAll(",", "")) < 1000) {
response.setSTATUS("Reject");
response.setREMARKS("Transaction Failed");
}
} else {
response.setSTATUS("Reject");
response.setREMARKS("Transaction Failed");
}
} else{
response.setPAYMENTMODE(null);
response.setVAN(null);
response.setAMOUNT(null);
response.setCREDITACCOUNTNUMBER(null);
response.setCUSTOMERCODE(null);
response.setTRANSACTIONDATE(null);
response.setADDINFO(null);
response.setSTATUS("Reject");
response.setREMARKS("Invalid Authentication");
JAXBContext jc = JAXBContext.newInstance(IPValAllField219Response.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
}
return response;
}
}
Note: Working code does the job without targetname spce but if I include targetname spce it gives me Null Pointer Exception Please Help on the above issue and thanks in advance.
I'm using Spring Boot's #RestController and there's (at least) two ways I can think of doing this:
Your endpoint method has a param of type HttpServletRequest which Spring automatically populates for you. Then, if you called it request, in your code you can do things like request.getHeader(HttpHeaders.AUTHORIZATION).
Your endpoint method has a param annotated with #RequestHeader("My-Header-Name") String myHeaderName, then in your code read myHeaderName as you need.
Have you tried:
#SoapHeader("{http://www.example.org/EcCustom67ARequest/}CUSTOMERNAME") ...,
#SoapHeader("{http://www.example.org/EcCustom67ARequest/}EMPID") ...
?
It looks like the right approach to set namespace on soap headers:
https://docs.spring.io/spring-ws/docs/current/org/springframework/ws/soap/server/endpoint/annotation/SoapHeader.html
https://docs.oracle.com/javase/8/docs/api/javax/xml/namespace/QName.html?is-external=true#toString--

SOAP Custom Response Header - JAX-WS

In my JAX-WS web service, I need to customize my SOAP Response Envelope.
At the moment, it is like this:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<methodResponse xmlns="http://interfaces.webservice.ucmdb.com">
<methodReturn>202</methodReturn>
</methodResponse >
</soapenv:Body>
</soapenv:Envelope>
And i need it to look like this:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Header>
<code>123</code>
</soapenv:Header>
<soapenv:Body>
<getCIResponse xmlns="http://interfaces.webservice.ucmdb.com">
<getCIReturn>202</getCIReturn>
</getCIResponse>
</soapenv:Body>
</soapenv:Envelope>
So, how does one write the <soapenv:Header> part in a JAX-WS soap envelope?
Here is my WebMethod implementation (quite simple at the moment):
#WebMethod
public int operation(#WebParam(name="username", header=false)String id) {
return 202;
}
1.) In order to add a header to your SOAP message in JAX-WS you can implement the SOAPHandler interface. This will give you access to the SOAPMessage and you can use the SAAJ api to add/update the SOAP Header. Keep in mind this handler is bi-directional.
public class Handler1 implements SOAPHandler<SOAPMessageContext>{
#Override
public boolean handleMessage(SOAPMessageContext context) {
boolean isOutbound = (boolean) context.get(SOAPMessageContext.MESSAGE_OUTBOUND_PROPERTY);
if(isOutbound){
SOAPMessage msg = context.getMessage();
try {
//Grab the header
SOAPHeader header = msg.getSOAPHeader();
//Add whatever QName you need
header.addHeaderElement(new QName("code"));
//Save changes.
msg.saveChanges();
} catch (SOAPException e) {
e.printStackTrace();
}
}
//True continue, false halt.
return true;
}
#Override
public boolean handleFault(SOAPMessageContext context) {
return false;
}
#Override
public void close(MessageContext context) {
}
#Override
public Set<QName> getHeaders() {
//Can also add a QName here.
return null;
}
}
2.) In order to register the Handler you need to add the handler via an xml handler configuration file that should be kept in the classpath.
<?xml version="1.0" encoding="UTF-8"?>
<javaee:handler-chains xmlns:javaee="http://java.sun.com/xml/ns/javaee">
<javaee:handler-chain>
<javaee:handler>
<javaee:handler-class>com.calvinmmiller.service.Handler1</javaee:handler-class>
</javaee:handler>
</javaee:handler-chain>
</javaee:handler-chains>
3.) This file can be added to the SEI(Service Endpoint Interface) with the annotation below:
import javax.jws.HandlerChain;
import javax.jws.WebService;
import javax.xml.ws.Endpoint;
#WebService
#HandlerChain( file = "handlerFile.xml")
public class Service {
public int operation(String id){
return 202;
}
public static void main(String[] args){
Endpoint.publish("http://localhost:8080/soap", new Service());
}
}

Getting content of a SOAP Header using Spring WS

I'm trying to build an endpoint that will receive SOAP messages from a client. The message I'm receiving contains a username and password inside the soap header ...
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns="http://www.company.com/Application">
<soapenv:Header xmlns:wsse="http://__________.xsd">
<wsse:Security >
<wsse:UsernameToken>
<wsse:Username>username</wsse:Username>
<wsse:Password>password</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
I'm using Spring WS - the obvious solution is to create a filter inside web.xml that will bypass Spring WS completely, parse the SOAP message, extract the username and password and then continue to Spring WS which will parse the SOAP again.
Is there a way to get the content of the header without circumventing Spring WS?
I've tried adding a bean inside sws:interceptors:
<sws:interceptors>
<!-- extract Security details from Header -->
<bean class="com.company.application.service.SecurityInterceptorService" />
<!-- log full Body of request -->
<bean class="org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor"/>
<!-- validate Request against XSD to make sure it's a valid request -->
<bean id="CompanyApplication" class="com.company.application.interceptor.ValidatingInterceptor">
<property name="schema" value="/WEB-INF/_______________.xsd" />
<property name="validateRequest" value="true" />
<property name="validateResponse" value="true" />
</bean>
</sws:interceptors>
and then implementing that class:
public class SecurityInterceptorService implements EndpointInterceptor {
#Override
public boolean handleRequest(MessageContext messageContext, Object endpoint) throws Exception {
System.out.println("---------------");
System.out.println("handleRequest") ;
System.out.println("---------------");
return true;
}
#Override
public boolean handleResponse(MessageContext messageContext, Object endpoint) throws Exception {
System.out.println("---------------");
System.out.println("handleResponse");
System.out.println("---------------");
return true;
}
#Override
public boolean handleFault(MessageContext messageContext, Object endpoint) throws Exception {
System.out.println("---------------");
System.out.println("handleFault");
System.out.println("---------------");
return true;
}
#Override
public void afterCompletion(MessageContext messageContext, Object endpoint, Exception ex) throws Exception {
System.out.println("---------------");
System.out.println("afterCompletion");
System.out.println("---------------");
}
}
endpoint only contains data about the endpoint inside handleRequest and after traversing through many layers and layers inside messageContext while in debug mode, I can't seem to spot the content of the header.
Is the content I'm looking for inside messageContext and if so, how do I access it?
From the messageContext object, you can retrieve either the request or the response (In your case, I guess you need the request).
The request/response is basically a WebServiceMessage. If you examine the webServiceMessage, you will see that the object can be casted to a SoapMessage. From the soap message, you can now get the soap header.
WebServiceMessage webServiceMessageRequest = messageContext_.getRequest();
SoapMessage soapMessage = (SoapMessage) webServiceMessageRequest;
SoapHeader soapHeader = soapMessage.getSoapHeader()
Afterwards, You might want to get the source object and convert it to a DOMSource object and then get the Node object which make the information retrieval much easier.
Source bodySource = soapHeader .getSource();
DOMSource bodyDomSource = (DOMSource) bodySource;
Node bodyNode = _bodyDomSource.getNode();
If you are using spring-boot you can use this kind of configuration:
#EnableWs
#Configuration
public class WebServiceConfig extends WsConfigurerAdapter {
#Override
public void addInterceptors(List<EndpointInterceptor> interceptors) {
PayloadValidatingInterceptor validatingInterceptor = new PayloadValidatingInterceptor();
validatingInterceptor.setValidateRequest(true);
validatingInterceptor.setValidateResponse(true);
validatingInterceptor.setXsdSchema(resourceSchema());
interceptors.add(validatingInterceptor);
}
#Bean
public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean(servlet, "/api/*");
}
#Bean(name = "registros")
public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema countriesSchema) {
DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
wsdl11Definition.setPortTypeName("ResourcePort");
wsdl11Definition.setLocationUri("/api");
wsdl11Definition.setTargetNamespace("http://resource.com/schema");
wsdl11Definition.setSchema(resourceSchema());
return wsdl11Definition;
}
#Bean
public XsdSchema resourceSchema() {
return new SimpleXsdSchema(new ClassPathResource("registro.xsd"));
}
}
In this example the addInterceptors method is the important one, the others 3 are basic to expose a WSDL API.
Maybe it'll be useful for someone else.
There is no easy way to unmarshall Soap headers with Spring-ws (it's currently not supported)
However, you can access the SoapHeaderElement in your #PayloadRoot annotated method, and do the process of unmarshalling with JAXB.
#Endpoint
public class SubmitEndpoint implements EndpointInterface {
private static final String NAMESPACE_URI = "http://www.example.com/namespace";
private Security unmarshallSecurityFromSoapHeader(SoapHeaderElement header) {
Security security = null;
try {
JAXBContext context = JAXBContext.newInstance(Security.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
security = (Security) unmarshaller.unmarshal(header.getSource());
} catch (JAXBException e) {
e.printStackTrace();
}
return security;
}
#PayloadRoot(namespace = NAMESPACE_URI, localPart = "submit")
#ResponsePayload
public SubmitResponse submit(#RequestPayload Submit submit, #SoapHeader(
value = "{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}Security") SoapHeaderElement wsseSecurityHeader) throws JAXBException {
Security security = unmarshallSecurityFromSoapHeader(wsseSecurityHeader);
}
}
Security.java
#Getter
#Setter
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(namespace = Security.SECURITY_NS, name = "Security")
public class Security {
public static final String SECURITY_NS = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
#XmlElement(namespace = SECURITY_NS, name = "UsernameToken")
private UsernameToken usernameToken;
}
UsernameToken.java
#Getter
#Setter
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(namespace = Security.SECURITY_NS, name = "UsernameToken")
public class UsernameToken {
#XmlElement(name = "Username", namespace = Security.SECURITY_NS)
private String username;
#XmlElement(name = "Password", namespace = Security.SECURITY_NS)
private String password;
}

Categories