JAX-WS Client throws SOAPFaultException instead of custom exception - java

I have a JAX-WS based application that I am developing. I generate WSDL from the server using wsgen and then build the client library using wsimport. I am writing my own custom exceptions to throw with my method calls. The code is structured as follows.
Custom Exception Class:
#WebFault(faultBean = "com.mysite.FaultBean")
public class MyCustomException extends Exception {
private FaultBean faultInfo;
//Getters/Setters/Constructors...
}
Custom Fault Bean:
public class FaultBean {
private String message;
private List<String> messages;
//Getters/Setters/Constructors...
}
I then throw MyCustomException from my methods in my web service endpoint. When I call one of my web service methods and it throws an exception the client is getting a SOAPFaultException instead of MyCustomException. Why is the custom exception not getting used?

So, after a bit of investigation it turns out the exceptions that were being thrown as a SOAPFaultException were not coming from where I thought they were. They actually were not thrown as MyCustomException. So, to solve this for all cases I took advantage of Spring AOP and created an Around aspect to wrap all of my calls to the web service implementation layer.
In this aspect I catch any exception thrown and wrap it in a MyCustomException before rethrowing it. My client can then handle the exception properly.

Related

How to map an exception thrown by a spring boot web service to a complex fault info?

I implement a service provider for an existing WSDL with Spring Boot. The WSDL specifies a service with an additional fault message. The corresponing fault info has some details including a timestamp, the class of the causing exception and its stack trace as well as information contained in the original request. All of the details are defined as XML elements on its own.
These information are available at runtime when the service is executed at the server. If an error occurs then an appropriate exception is thrown which contains these information.
With spring boot one can configure an instance of org.springframework.ws.server.EndpointExceptionResolver
to map exceptions to fault infos. However, it seems that in all its implementing classes it is only possible to add a fault info message and a fault code. I did not find a way to add a structured object or better: an object for which a JAXB serialization is defined.
How is this possible?
Sure that's not a problem.
One way could be to create a custom SoapFaultMappingExceptionResolver that maps the exception to the fault:
public class DetailSoapFaultDefinitionExceptionResolver extends SoapFaultMappingExceptionResolver {
private static final QName CODE = new QName("code");
private static final QName DESCRIPTION = new QName("description");
#Override
protected void customizeFault(Object endpoint, Exception ex, SoapFault fault) {
logger.warn("Exception processed ", ex);
if (ex instanceof ServiceFaultException) {
ServiceFault serviceFault = ((ServiceFaultException) ex).getServiceFault();
SoapFaultDetail detail = fault.addFaultDetail();
detail.addFaultDetailElement(CODE).addText(serviceFault.getCode());
detail.addFaultDetailElement(DESCRIPTION).addText(serviceFault.getDescription());
}
}
}
Please find a complete example here:
https://memorynotfound.com/spring-ws-add-detail-soapfault-exception-handling/

Bind Exception Handling to #ControllerAdvice class only

I have a controller class with REST methods that can throw various exceptions. I have decided to handle these exceptions in a separate class using the #ControllerAdvice and #ExceptionHandler for my handler methods.
However, I have the problem, that my REST methods use an annotation from another library. This library catches an exception that my REST method throws as well.
Now that I am handling the exceptions globally and not via try/catch in the REST method directly, my exception is always caught by the other library and not by my own handler method. Apparently, that other method in the library I am using wins due to the annotation.
How can I bind the exception handling to my own class to prevent it from being caught by anyone else?
My REST method:
#SomeLibraryAnnotation
#PostMapping(path = "/add", consumes = MediaType.APPLICATION_JSON_VALUE)
public HttpEntity< ? > addItem(#RequestHeader HttpHeaders headers, #RequestBody MyDTO myDTO)
throws UnsupportedOperationException {
doSomethingWith(myDTO);
return ResponseEntity.status(HttpStatus.CREATED).build();
}
My Exception Handler class:
#ControllerAdvice
public class MyExceptionHandler {
#ExceptionHandler(UnsupportedOperationException.class)
public ResponseEntity<?> handleUnsupportedOperationException(UnsupportedOperationException e) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(e.getMessage());
}
}
As the library method also catches the UnsupportedOperationException, it wins due to the #SomeLibraryAnnotation and the exception is never handled in my handler class.
You might try using #Order or #Priority in the MyExceptionHandler class, as discussed in Setting Precedence of Multiple #ControllerAdvice #ExceptionHandlers.
That would give Spring an opportunity to use your class instead of the one specified by the #SomeLibraryAnnotation. However, without knowing how Spring interprets that other annotation at context initialization, that's just a guess.
Did you tried to write #ExceptionHandler inside your controller? Like:
#RestController
#RequestMapping("/path")
public class TheController {
#ExceptionHandler(UnsupportedOperationException.class)
public ResponseEntity<?> handleUnsupportedOperationException(UnsupportedOperationException e) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(e.getMessage());
}
}
Maybe that would pickup and exception with higher priority. It's hard to answer not knowing what #SomeLibraryAnnotation is...
Those are simply Java Language rules, i.e. exception is no longer unhandled, as it was handled (caught in a catch block) by your other library. What you can do it is to re-throw (maybe conditionally) another exception in your library which caught original exception and see if #ExceptionHandler will handle it. It might not because #ExceptionHandler is handling exceptions thrown in Controller classes.
Second approach would be to throw exception which is only handled in #ExceptionHandler and then re-throw it be handled in other library.
In other words you need to choose where to handled first originally thrown exception.
Third approach would be use AOP interceptor #AfterThrowing or #Around and then execute whatever logic you want within.
Essence : There is no way to handle exception in two places at one time. Does it make sense?

Use ExceptionMapper to log CLIENT_ERRORs

I am working on an application which uses Dropwizard, which has this implementation of ExceptionMapper: https://github.com/dropwizard/dropwizard/blob/master/dropwizard-jersey/src/main/java/io/dropwizard/jersey/errors/LoggingExceptionMapper.java
Problem with this implementation is that even though this catches both 4** and 5** errors, it only logs 5** errors.
I need to implement ExceptionMapper such that LoggingExceptionMapper is not used at all and my CustomExceptionMapper logs both CLIENT_ERRORs and SERVER_ERRORs.
I am wondering how would my application know that it needs to use CustomExceptionMapper instead of the Dropwizard class?
Also would it suffice to add CLIENT_ERROR to if condition, to log out all errors?
#Override
public Response toResponse(E exception) {
// If we're dealing with a web exception, we can service certain types of request (like
// redirection or server errors) better and also propagate properties of the inner response.
if (exception instanceof WebApplicationException) {
final Response response = ((WebApplicationException) exception).getResponse();
Response.Status.Family family = response.getStatusInfo().getFamily();
if (family.equals(Response.Status.Family.REDIRECTION)) {
return response;
}
if (family.equals(Response.Status.Family.SERVER_ERROR) || family.equals(Response.Status.Family.CLIENT_ERROR) {
logException(exception);
}
return Response.fromResponse(response)
.type(MediaType.APPLICATION_JSON_TYPE)
.entity(new ErrorMessage(response.getStatus(), exception.getLocalizedMessage()))
.build();
}
Or would there be a better way to do this?
JAX-RS spec about ExceptionMapper:
When choosing an exception mapping provider to map an exception, an
implementation MUST use the provider whose generic type is the nearest
superclass of the exception.
How would my application know that it needs to use CustomExceptionMapper instead of the Dropwizard class?
You can throw a custom exception from your application and create an ExceptionMapper for that specific exception.
Would it suffice to add CLIENT_ERROR to if condition, to log out all errors?
Yes, 4xx and 5xx family has all the error responses.

The best way of exception handling in an app with web services

I have an application which consists of SOAP and REST web services and a simple HTTP access. All of them convert incoming requests and send them to a handler. The most painful thing is exception handling. In order to return the right response, I have to wrap every method with try-catch block and create a response there.
I thought that I could create a filter which could do it. But how can the filter recognise the source of it (soap, rest frontend) so I knew that I should return a SOAP or other response?
It depends on the WS framework you use. All I know have some sort of interceptors/aspects that you can inject and handle exceptions in one place. For instance in apache-cxf there is even a special outbound error chain where you can plug your own interceptors.
Obviously try-catch in every method is a bad idea.
In layer of below Web-Service Layer, you have to create your custom Exception and in Web-Service layer you have to use try-catch approach for achieve occurred exception and in catch block log and convert it to your custom web service layer exception. I show this approach in following:
#WebService
public class EmployeeWS
{
#WebMethod
public void add(Employee em) throws CustomWebServiceException
{
try
{
// call facade layer method
}
catch(Exception e)
{
logger.error(e.getMessage());
throw new CustomWebServiceException(e);
}
}
}
Alternative using try catch in any Web-Method,you can use AOP approch(for sample Spring AOP) or interceptor approach in Web-Service frameworks(for sample SOAPHandler<T> in JAX-WS).
Note: In JAX-WS standard, you can't throw a RuntimeException because Exception must specify in final WSDL and if you throw a RuntimeException your web service client don't achieve your CustomException, in another your Web-Methodneed to throws in itself signature.
You can see selected Web-Service faramework documents for more information.
It sounds that you are not using any framework because that was typical frameworks provide. For example Spring allows you to decouple the code from exception handling and define your custom exception handlers.
In your case you generally have 2 solutions.
(1) You can use Decorator pattern: wrap each service with decorator where each method is implemented as
try {
call real method
} catch() {
send error to client
}
Since it is very verbose you can save time using Dynamic proxy (feature that was introduced in java 5). So, you can dynamically wrap each service (if your services have defined interface).
(2) You can solve it using servlet API's error page:
javax.servlet.ServletException
/servlet/ErrorDisplay
for more details see http://java.sun.com/developer/technicalArticles/Servlets/servletapi2.3/
You can customize your class!! Do it!
Take easy on diagnostic errors, like insert a protocol number, message Log, message client, etc...
http://java.globinch.com/enterprise-java/web-services/jax-ws/jax-ws-exceptions-faults-annotation-exception-and-fault-handling-examples/#Pre-Requisites

How to hide RuntimeException details from EJB client?

I have a JEE5 application that exposes services using (local) session beans.
When an internal fault occurs during service execution, a RuntimeException is thrown and encapsulated by JBoss(5.0.1) in a javax.ejb.EJBTransactionRolledbackException.
The problem is that client applications receiving this EJBTransactionRolledbackException can access detailled informations about the cause runtime exception, exposing internal architecture of my application. And I don't want that.
Instead, I would like JBoss to always encapsulate RuntimeException thrown by exposed session beans into a single (and simple) TechnicalException (with no cause).
What's the best way to achieve this ? (Using interceptors ? Using JBoss configuration ?)
Finally, based on previous answer and my personal researches, I retained the folowing solution.
I've created an interceptor dedicated to manage server faults :
public class FaultBarrierInterceptor {
#AroundInvoke
public Object intercept(final InvocationContext invocationContext) throws Exception {
try {
return invocationContext.proceed();
} catch (final RuntimeException e) {
final Logger logger = Logger.getLogger(invocationContext.getMethod().getDeclaringClass());
logger.error("A fault occured during service invocation:" +
"\n-METHOD: " + invocationContext.getMethod() +
"\n-PARAMS: " + Arrays.toString(invocationContext.getParameters()), e);
throw new TechnicalException();
}
}}
The thrown technical exception extends EJBException and does not expose the cause RuntimeException:
public class TechnicalException extends EJBException {}
I use this interceptor in all public services :
#Stateless
#Interceptors({FaultBarrierInterceptor.class})
public class ShoppingCardServicesBean implements ShoppingCardServices { ...
This is an implementation of the Fault Barrier pattern.
Any runtime exception is catched, logged and a fault is signaled to the client (without internal details) using a TechnicalException. Checked exceptions are ignored.
RuntimeException handling is centralized and separated from any business methods.
Any RuntimeException extends java.lang.Exception.
The EJB spec provides handling for 2 types of exceptions (Application and System)
If you'd like to throw a System Exception, you would usually do it like so:
try {
.... your code ...
}catch(YourApplicationException ae) {
throw ae;
}catch(Exception e) {
throw new EJBException(e); //here's where you need to change.
}
To hide the internal details of your system exception, simply replace:
throw new EJBException(e);
with:
throw new EJBException(new TechnicalException("Technical Fault"));
Hope this is what you were looking for.
Cheers

Categories

Resources