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)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.