SOAP Request data is not going to External System in SpringBoot - java

I am trying to send request data to external soap server but data is going to null in the request to External Soap Server.
Please find the code as below:
UserListResponse response = null;
#PayloadRoot(namespace = NAMESPACE_URI, localPart = "UserList")
#ResponsePayload
public UserListResponse UserListRequest(#RequestPayload UserListRequest request) throws Exception {
System.out.println("Enters into UserList()");
try {
//Client call
UserServicesLocator locator = new UserServicesLocator();
UserServicesSoapStub stub = (UserServicesSoapStub) locator.getUserServicesSoap();
response = stub.userList(request);//here the request data values not mapping at external system side
} catch(Exception e) {
e.printStackTrace();
}
return response;
}
SOAP UI Request:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:prim="http://*****/UserServices">
<soapenv:Header/>
<soapenv:Body>
<prim:UserList>
<!--Optional:-->
<prim:XMLRequest>
<!--Optional:-->
<prim:Header>
<!--Optional:-->
<prim:MessageID>1</prim:MessageID>
<!--Optional:-->
<prim:CorrelationID>1</prim:CorrelationID>
<!--Optional:-->
<prim:SystemID>C</prim:SystemID>
<!--Optional:-->
<prim:RequestorID>1</prim:RequestorID>
</prim:Header>
<prim:Reference>Account</prim:Reference>
<!--Optional:-->
<prim:Number>100987600</prim:Number>
</prim:XMLRequest>
</prim:UserList>
</soapenv:Body>
</soapenv:Envelope>
The request is hitting the External Soap server but Soap server getting the all values (both Header & Body data)in the request as null.
I am unable to get why the values are going to null even i am passing the values from SOAP UI.
I am not getting even i am doing anything wrong here.Can anyone please help on this.

Related

javax post request endpoint throws null pointer exception

We get the following error:
WARNING [org.apache.cxf.phase.PhaseInterceptorChain] (default task-1) Interceptor for {http://localhost:8080/endpoint/HelloWorldService}HelloWorldService#{http://localhost:8080/endpoint/HelloWorldService}postXML has thrown exception, unwinding now: java.lang.NullPointerException
I won't even bother adding the full stack trace, because it is filled with useless junk.
We have a prototype method in an interface like this:
#Path("/postxml")
#POST
#Consumes(MediaType.APPLICATION_XML)
#Produces(MediaType.APPLICATION_XML)
//#XmlElement(namespace = "http://localhost:8080/endpoint/HelloWorldService")
//#WebResult(name="postxml", targetNamespace="http://localhost:8080/endpoint/HelloWorldService")
String postXML(String xml);
//#QueryParam("customerId")
//#WebParam(name="customerId", targetNamespace="http://localhost:8080/endpoint/HelloWorldService") int customerId
We override this method in the class, which is implementing the interface like so:
#Override
public String postXML(String xml) {
/*return Response.ok(xml)
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Methods", "POST, GET, PUT, UPDATE, OPTIONS")
.header("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With")
.build();
*/
return "test";
}
What we tried so far:
changing the order of the annotations
we tried out the lines of code that are currently commented out
we looked at other examples on github
we tried changing the return type from String to Response
The problem is:
we either get a CORS error, a NULL Pointer Exception or sometimes both.
The expected result should be:
receive XML data through a POST request and echo it via XHR from our frontend.
To send the POST request we used the following javascript code:
function XMLXHRRequest() {
var url = "http://localhost:8080/endpoint/HelloWorldService";
var xhr = new XMLHttpRequest();
//xhr.withCredentials = true;
xhr.open("POST", url, true);
//xhr.setRequestHeader("Content-Type", "application/soap+xml");
//xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
//xhr.setRequestHeader('Access-Control-Allow-Origin', '*');
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status == 200) {
console.log(xhr.status);
console.log(xhr.responseText);
}
};
const data = `<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:hel="http://localhost:8080/endpoint/HelloWorldService">
<soapenv:Header/>
<soapenv:Body>
<hel:postXML>
<!--Optional:-->
<arg0>?</arg0>
</hel:postXML>
</soapenv:Body>
</soapenv:Envelope>`;
xhr.send(data);
}
We also have the following question:
Why does SoapUI append the prefix hel before the method call in SOAP ?

Soap Response without namespaces

I have received below response in Java Spring Boot ws application:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/">
<soapenv:Header>
<dateTime>23082020033057</dateTime>
</soapenv:Header>
<soapenv:Body>
<TestResponse>
<ResponseCode>06</ResponseCode>
</TestResponse>
</soapenv:Body>
</soapenv:Envelope>
I'm parsing response in SOAPHandler class.
public class HeaderHandler implements SOAPHandler<SOAPMessageContext> {
private static final String SOAP_ENV_NAMESPACE = "http://schemas.xmlsoap.org/soap/envelope/";
private static final String PREFERRED_PREFIX = "soapenv";
public boolean handleMessage(SOAPMessageContext smc) {
SOAPMessage message = smc.getMessage();
}
}
I received below error message.
**javax.xml.ws.WebServiceException: com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl: HeaderElements must be namespace qualified**

JAX-WS Handler Ignoring Fault Sub-elements

I'm implementing a web service client using JAX-WS over SOAP. Its error codes are returned in the following way:
<?xml version = '1.0' encoding = 'UTF-8'?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<env:Header>
<!-- header stuff goes here -->
</env:Header>
<env:Body>
<env:Fault>
<abc:fault xmlns:abc="http://example.com/abc">
<abc:faultcode>12345</abc:faultcode>
<abc:faultstring>Error message goes here</abc:faultstring>
</abc:fault>
</env:Fault>
</env:Body>
</env:Envelope>
As far as I know, this is not the correct way to do SOAP faults. The subelements of a env:Fault should be <faultcode> and <faultstring>, not a different namespaced <fault>. Unfortunately, I have no way of making the web service change this.
My hope was that I would be able to parse this message in a SOAPHandler and transform it into a regular fault before passing it on to the rest of my code, however when I logged the message in an earlier Handler I saw that the Fault element completely empty. The <abc:fault> was gone!
I'm using JAX-WS on WebSphere 7 and I've tried setting "jaxws.payload.highFidelity" to true in my system properties. Any clues on to how to get at the original message?
Leaving this alone will cause a WebServiceException with a NullPointerException because JAX-WS can't find the faultcode.
So I found the answer to my question. WebSphere 7 uses Axis2. Axis2's MessageContext provides a property called "TRANSPORT_IN" which contains a ByteArrayInputStream. TRANSPORT_IN, as the name implies, contains the exact SOAP message received.
I parsed through the original SOAP message in my Handler#handleFault method using a SAXHandler to retrieve the abc:fault message. I then wrote the abc:fault > faultcode and faultstring to the soapenv:Fault faultcode and faultstring. My application then handles the SOAPFaultException as if it was a normal one.
I'm still very open to any better answers since this feels like roundabout way to do this.
Handler Code:
public boolean handleFault(SOAPMessageContext context) {
SOAPMessage m = context.getMessage();
if(m != null) {
SOAPBody body = m.getSOAPBody();
SOAPFault fault = body.getFault();
setAbcFault(fault, context);
}
}
private void setAbcFault(SOAPFault fault, MessageContext context) {
ByteArrayInputStream bis = (ByteArrayInputStream)context.get("TRANSPORT_IN");
// do sax parsing on the input stream
fault.setFaultCode(abcFaultCodeQName);
fault.setFaultString(abcFaultString);
}
If you are using JAX-WS, you can use SOAP faults. or that, you need an Exception with #WebFault annotation. You can find a good example in Using SOAP Faults and Exceptions in Java JAX-WS Web Services - Eben Hewitt on Java.
See the answer for returning null or throw exception and How to throw a custom fault on a JAX-WS web service?
Example:
#WebService
public class CalculatorWS {
public String factorial(int n) throws FactorialException {
if (n < 0) {
throw new FactorialException("Negative number!", // faultstring
"The number n = " + n); // detail
}
return BigIntegerMath.factorial(n).toString();
}
}
With:
public class FactorialException extends Exception {
String detail;
public FactorialException(String message, String detail) {
super(message);
this.detail = detail;
}
public String getFaultInfo() {
return detail;
}
}
If the request is:
<soapenv:Envelope ... >
<soapenv:Header/>
<soapenv:Body>
<test:factorial>
<arg0>-1</arg0>
</test:factorial>
</soapenv:Body>
</soapenv:Envelope>
The response is:
<soapenv:Envelope ... >
<soapenv:Body>
<soapenv:Fault>
<faultcode>soapenv:Server</faultcode>
<faultstring>Negative number!</faultstring>
<detail>
<ns2:FactorialExceptionBean xmlns:ns2="http://...">
The number n = -1
</ns2:FactorialExceptionBean>
</detail>
</soapenv:Fault>
</soapenv:Body>
</soapenv:Envelope>
(Tested in Websphere 7)

Spring WS with jaxb null object in request

I have Spring WS to which i am sending request of Object Request.java class, if i hardcode value in jaxb class it is ok ( but this is not it..)
my soap request i test in SoapUI:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:cas="http://jakisadres.com/caservice">
<soapenv:Header/>
<soapenv:Body>
<cas:Request>
<cas:atr1>some value</cas:machineName>
</cas:Request>
</soapenv:Body>
</soapenv:Envelope>
and what i get is :
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
<ns3:Response xmlns:ns3="http://jakisadres.com/caservice">
<responseValue>response: null</responseValue>
</ns3:CARevokeCertResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
my endpoint:
#PayloadRoot(localPart = "Request", namespace = "http://jakisadres.com/caservice")
#ResponsePayload
public Response revokeCert(#RequestPayload Request param) {
String request= param.getAtr1();
Resoponse response_ = new Response();
response.setResponseValue("response: "+request);
return response;
}
and my jaxb marshaller class:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"atr1"
})
#XmlRootElement(name = "Request")
public class Request{
protected String atr1;
public String getAtr1() {
return atr1;
}
public void setAtr1(String value) {
this.atr1 = value;
}
}
any clue what am I missing?
Probably your atr1 element is in the default namespace and not in http://jakisadres.com/caservice namespace..your request should either be:
<cas:Request>
<atr1>some value</atr1>
</cas:Request>
OR you can explicitly specify the namespace for atr1 field

How do I access SOAP headers in a spring soap endpoint?

Here is my SOAP request:
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:str="http://app.strategyblocks.com/ws/schema/strategyblocks">
<soapenv:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" soapenv:mustUnderstand="1">
<wsse:UsernameToken xmlns:wsu="...">
<wsse:Username>admin</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">secret</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
<str:updateKpiRequest>
<str:company_id>1</str:company_id>
<str:kpi>
<str:external_id>1134511</str:external_id>
<str:title>title</str:title>
<str:description>description</str:description>
</str:kpi>
</str:updateKpiRequest>
</soapenv:Body>
</soapenv:Envelope>
Here is my Endpoint class:
#Endpoint
public class UpdateKpiEndpoint {
// The namespace of both request and response as declared in the XSD file
public static final String NAMESPACE_URI = "http://app.strategyblocks.com/ws/schema/strategyblocks";
// The local name of the expected request.
public static final String REQUEST_LOCAL_NAME = "updateKpiRequest";
#PayloadRoot(localPart = REQUEST_LOCAL_NAME, namespace = NAMESPACE_URI)
#ResponsePayload
public UpdateKpiResponse processUpdateKpi(#RequestPayload UpdateKpiRequest updateKpiRequest) {
try {
} catch (Exception e) {
UpdateKpiResponse response = new UpdateKpiResponse();
response.setCode("FAILURE");
response.setDescription("Problem with update kpi request");
return response;
}
UpdateKpiResponse response = new UpdateKpiResponse();
response.setCode("SUCCESS");
response.setDescription("Kpi has been updated");
return response;
}
}
At the moment I am passing a UsernameToken for authentication in the soap request, that is all working well and I have no problems with it what so ever. What I want to be able to achieve is to retrieve that username from the header in the body of processUpdateKpi method in my endpoint class, so that I can use it to find existing data for that user, I have tried to find examples of it being done and so far I have been unsuccessful, is it possible to do it? I have thought about also passing the username in the SOAP body as well, but I want to avoid it.
someone in the spring forums had a clear explanation on how to read the header from the endpoint class:
http://forum.springsource.org/showthread.php?109560-Unable-to-read-SoapHeader-in-Endpoint-class

Categories

Resources