Java Spring Web Service Client Fault Handling - java

I have written a web service client (using Java Spring and JAXB Marshaller) that works with the UPS web service. When I send a valid request everything works well. When I send an invalid request (weight > 150 lbs) then the UPS web service responds with a SOAP Fault. The client application just fails with a
org.springframework.oxm.UnmarshallingFailureException: JAXB unmarshalling
exception; nested exception is javax.xml.bind.UnmarshalException:
unexpected element (uri:"http://schemas.xmlsoap.org/soap/envelope/", local:"Fault").
Obviously my program isn't able to decipher the SOAP fault returned by the web service. I wrote a custom FaultMessageResolver, but it doesn't get invoked. Here's the code:
public class UpsRateClient extends WebServiceGatewaySupport {
public UpsRateClient(WebServiceMessageFactory messageFactory) {
super(messageFactory);
getWebServiceTemplate().setFaultMessageResolver(new UpsFaultMessageResolver());
}
public RateResponse getRate(RateRequest rateRequest) {
return (RateResponse) getWebServiceTemplate().marshalSendAndReceive(rateRequest, new UpsRequestWSMC());
}
private class UpsFaultMessageResolver implements FaultMessageResolver {
public void resolveFault(WebServiceMessage message) throws IOException{
System.out.println("Inside UpsFaultMessageResolver");
}
}
}
Thanks for your time!

I had the same problem (SOAP error with HTTP 200OK) and I solved it setting the CheckConnectionForFault property to false. See.

Take a wireshark trace.My thought is that perhaps the web service sends the SOAP fault using (erroneously) a HTTP 200OK instead of a 500 Internal Server error and your client tries to handle it as a valid response.
If this is the case this is then the problem lies in the web service which does not addere to SOAP standard(my emphasis):
From SOAP RFC
In case of a SOAP error while processing the request, the SOAP HTTP
server MUST issue an HTTP 500 "Internal Server Error" response and
include a SOAP message in the response containing a SOAP Fault element
(see section 4.4) indicating the SOAP processing error.
If you do not own the web service, they should fix this.
To be honest I am not sure what the work arround would be in Spring-WS.
If I really needed a work arround in Jax-Ws I would replace the stub call with a Dispatcher to handle the raw xml myself and avoid the automatic marshal/demarhal.
Look into Spring-Ws if you can do the same, but this is a bug of the web service, not your client

Related

Spring-WS does not marshall the request object. Empty request is sent

I am calling a SOAP webservice in a Spring Boot project using Spring WebserviceTemplate. My client class extends WebServiceGatewaySupport. I cannot post the actual code, but this is a sample.
Response response = (Response) getWebServiceTemplate().marshalSendAndReceive(request, new SoapActionCallback("http://tempuri.org/rpc/Gateway/"));
When this request is sent, I am getting response code 400. I enabled trace logging for Spring and found that an empty request is sent.
TRACE o.s.ws.client.MessageTracing.sent.sendRequest - Sent request []
When I tried to create a simpler web service client using the same components - Spring Boot project using Spring WebserviceTemplate, I can see that it sends a valid XML payload and it works.
I have now found that this error happens only as part of a larger existing project - the request object being marshaled as an empty string. It is just sending an empty payload. There are no errors in the log before the call is made to webservice.
The request and response POJO are generated by maven-jaxb2-plugin & I have verified that the package and schema are correct.
I have verified that the Marshaller (Jaxb2Marshaller) and its context path are set correctly, and it marshals the request object when called separately.
How can I debug this? Please give your suggestions.

ClientInterceptor - capturing 404 scenarios

I am using ClientInterceptor to intercept all the external soap calls made by my application and log the request and response. I am able to capture the request / response and fault scenarios. However when I see a 404 error due to endpoint being incorrectly configured , I am unable to capture this using the methods provided by this interface. Is there a way to capture 404 error using this interface? If not , can you please help in letting me know the alternative that I need to explore?
org.springframework.ws.client.support.interceptor.ClientInterceptor
The org.springframework.ws.client.support.interceptor.ClientInterceptor.handleFault() only suits for intercepting the processes of incoming response fault. That is the SOAP faults defined by specification. So the SOAP 1.1 and 1.2 specifications define a status codes which are returned in case of SOAP fauls (for example in case of malformed XML in the request message envelope). SOAP 1.1 specifies a 500 status code for faults and SOAP 1.2 specifies a 400 status code for sender faults, and 500 for all other faults. In case of faults the server returns SOAP message in the response containing a SOAP Fault element which then can be passed to the ClientInterceptor.handleFault() methods. But 404 status code indicates that it is not a SOAP failure but system error. So if you need to handle that case as well you need to overwrite the WebServiceTemplate.handleError() method instead.
This will do the trick
public class CustomWebServiceTemplate extends WebServiceTemplate{
#Override
protected Object handleError(WebServiceConnection connection, WebServiceMessage request) throws IOException {
log.info("Log the error case in here");
return super.handleError(connection, request);
}
}

Get HTTP response code from JAX-WS asynchronous web service

I have an asynchronous JAX-WS web service (#WebService and #WebMethod annotations). I am invoking it in Java. and I would like to know how to get HTTP response code from that service in Java code.
I couldn't find anything on that subject, but I deduced solution based on how my request context is built, because I needed response context so I thought they may be similar. Request context:
((BindingProvider)port).getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpoint)
So I thought that this may work:
int responseCode = (int)((BindingProvider) port).getResponseContext().get(MessageContext.HTTP_RESPONSE_CODE);
And it works. ; )

ValidationError in Jersey Client?

I'm having trouble getting ValidationErrors from a jersey resource in jersey client. Let me explain.
A function in jersey resource:
#POST
#Produces({ MediaType.APPLICATION_JSON })
#Consumes(MediaType.APPLICATION_JSON)
public LoginInfo login(#NotNull #Valid Login login)
My clientconfig:
ClientConfig clientConfig = new ClientConfig();
clientConfig.register(JacksonFeature.class);
My jersey client:
ClientBuilder.newClient(getClientConfig())
And my function call:
getTarget("/login").request(MediaType.APPLICATION_JSON_TYPE).post(Entity.json(login), LoginInfo.class);
All works without problems as long i supply valid parameters, when i for example supply null as parameter i get exception:
HTTP 400 Bad Request
But i'm expecting a ValidationError response, because bean validation failed.
Bean validation and error response is working on server, for example with a simple html test, which shows validationerror structure:
<div class="validation-errors"><div class="validation-error"><span class="message">may not be null</span> (<span class="path"><strong>path</strong> = LoginResource.login.arg0</span>, <span class="invalid-value"><strong>invalidValue</strong> = null</span>)</div></div>
How do i get the ValidationError in my jersey client? Do i maybe have to configure it in a special way or maybe i should use a filter?
[edit]
I turned on tracing and when validation fails on server the server sends validationerrors, but it seems jersey client doesn't do anything with it, it converts it to BadRequestException.
6 < 400
6 < Content-Type: application/json
6 < Vary: Accept
[{"message":"may not be empty","messageTemplate":{org.hibernate.validator.constraints.NotBlank.message}","path":"RuleResource.add.arg0.description","invalidValue":""}]
Answering my own question ;-)
It seems jersey client doesn't support validationerrors, so i created a client filter and when status is 400 i get the entity and put the validation errors in a list. Next i create a validationexception which includes the validation errors and just throw it. A bit further up the chain i get a processingexception, in the stacktrace the validationexception can be found and also the validation errors. So i create a nice message from the validation errors and throw another exception, all the way up to my gui code which simply displays the exception message.
Works fine, thanks jersey for the flexibility of filters!

How to consume text/plain response with Restlet 2.1 from GWT client?

I have a GWT client that would like to query a RESTful service that returns text/plain. I created a proxy interface:
public interface ConnectionStatusService extends ClientProxy
{
#Get("txt")
public void getVersion(Result<String> callback);
}
But when I'm using the generated proxy class:
ConnectionStatusService service = GWT.create(ConnectionStatusService.class);
it sends a request that accepts Accept application/x-java-serialized-object+gwt according to Firebug, so the server returns HTTP 406 Not Acceptable of course.. :-( How could I make it accept plain text?
I'm using resty-gwt to create restfull web services but I'm not accessing it now from GWT client classes. They have documentation where it's documented.
Hope that helps.

Categories