Here is my fault interceptor:
public class OutFaultInterceptor extends AbstractPhaseInterceptor<Message> {
public OutFaultInterceptor() {
super(Phase.SEND);
}
#Override
public void handleMessage(Message message) throws Fault
{
Fault fault = (Fault)message.getContent(Exception.class);
Throwable ex = fault.getCause();
Response response = JAXRSUtils.convertFaultToResponse(ex, message);
message.setContent(Response.class, response);
}
}
Here is my relevant cxf-config:
<jaxrs:outFaultInterceptors>
<bean id="outfault" class="com.xxx.OutFaultInterceptor"/>
</jaxrs:outFaultInterceptors>
I can get into the handleMessage method no problem, but I'm not able to modify the message.
Currently what it returns is the default: ns1:XMLFault blah blah...
What I want to return is a Response object that has a proper HTTP response code and a json body (which I correctly have in my response variable above).
Thanks
If you're using JAX-RS, why not setup an exception mapper, and then use that mapper to handle the response.
A simple example:
#Provider
#Produces(MediaType.APPLICATION_JSON)
public class MyExceptionMapper implements
ExceptionMapper<MyException> {
#Override
public Response toResponse(MyException e) {
return Response.status(Status.NOT_FOUND).build();
}
}
Then you would need to register the provider in the jaxrs serve by adding:
<jaxrs:providers>
<bean class="com.blah.blah.blah.blah.MyExceptionMapper"/>
</jaxrs:providers>
in the server config in the context. With that you have full access to the exception, and can get whatever you want from it.
Related
java 8, spring, rest
I am trying to capture the Response that comes from exception mapper, and do something with it in the caller which throws the exception. Thanks.
#Provider
public class CustomerExceptionHandler implements ExceptionMapper<CustomerException>
{
#Override
public Response toResponse(CustomerException exception)
{
return Response.status(Status.BAD_REQUEST).entity(CustomerException.getMessage()).build();
}
}
public class CustomerException extends Exception implements Serializable
{
private static final long serialVersionUID = 1L;
public CustomerException() {
super();
}
public CustomerException(String msg) {
super(msg);
}
public CustomerException(String msg, Exception e) {
super(msg, e);
}
}
public class ExceptionDemo{
public void getExceptionResponse(){
//do something
throw new CustomerException("Something is wrong");// CustomerExceptionHandler is going to return me a Response, how can I capture the response here?
//capture response and do something with it
}
}
I'm not sure ExceptionMappers work in the way you think they do.
When some code in the endpoint throws an exception, and this exception percolates all the way out of the endpoint and back into the container itself (Spring in this case), then the registered ExceptionMappers are consulted to see if they match the thrown exception, and the relevant one's public Response toResponse(T e) {} method is called to transform it into a Response.
The ExceptionMapper doen't get called as part of your endpoint code, and you won't be able to take action based on its resultant Response because it hasn't yet been called. You just need to throw the exception out of the endpoint.
So I am build an mvc application using Jersey. A method that accepts Path parameters (#PathParam).
If a custom exception is thrown (ExampleException) then a 404 Not Found response is returned using an exception mapper.
#Provider
public class ExampleExceptionMapper implements ExceptionMapper<ExampleException> {
#Override
public Response toResponse(ExampleException ex) {
return Response.status(Status.NOT_FOUND).entity("Not Found - " + ex.getMessage()).build();
}
}
However, I am implementing #FormParam's so a user POSTs to the server. The same exact exception is raised, but instead I should return a 400 Bad Request response. Without modifying the exception how would I be able to make the exception mapper return the proper response code?
Simplest way is create multiple ExceptionMappers, each for specific subclass of ExampleException.
But you want to have the same exception for both cases and decide whether to throw 404 for GET/PathParam and POST/FormParam, you can inject the request into the mapper and check what method it is:
#Provider
public class ExampleExceptionMapper implements ExceptionMapper<ExampleException> {
#Context Request request;
#Override
public Response toResponse(ExampleException ex) {
if ("POST".equals(requset.getMethod()))
return Response.status(Status.BAD_REQUEST).build();
else
return Response.status(Status.NOT_FOUND).entity("Not Found - " + ex.getMessage()).build();
}
}
If you want to decide by PathParams, you can inject UriInfo:
#Provider
public class ExampleExceptionMapper implements ExceptionMapper<ExampleException> {
#Context UriInfo info;
#Override
public Response toResponse(ExampleException ex) {
if (info.getPathParameters().isEmpty())) //please make better condition based on your needs
return Response.status(Status.BAD_REQUEST).build();
else
return Response.status(Status.NOT_FOUND).entity("Not Found - " + ex.getMessage()).build();
}
}
Here,my requirement is that i want separate code in my application for exception handling,i saw a nice option of spring there using #controller advice to handle exceptions globally.
#ControllerAdvice
class GlobalControllerExceptionHandler {
#ResponseStatus(HttpStatus.CONFLICT) // 409
#ExceptionHandler(DataIntegrityViolationException.class)
public void handleConflict() {
// Nothing to do
}
}
But there i want to cutomization there,like proper dynamic messages,own error code. so how can i do this,i am new to spring boot and even i don't have knowledge of spring.Need basic example.
You can come up with a class like this to capture information to be sent in response in case of exception:-
public class APIResponse {
int errorCode;
String description;
String someInformation;
// any other information that you want to send back in case of exception.
}
#ControllerAdvice
class GlobalControllerExceptionHandler {
#ResponseStatus(HttpStatus.CONFLICT) // 409
#ResponseBody
#ExceptionHandler(DataIntegrityViolationException.class)
public APIResponse handleConflict(DataIntegrityViolationException exception) {
APIResponse response = createResponseFromException(exception);
return response;
}
}
In your controller advice class:-
Have the return type APIResponse instead of void.
The handler method can have the exception raised as the argument.
Using the exception object to create the APIResponse object.
Put #ResponseBody on the handler method.
I need to catch response from SOAP webservice I'm calling.
I've implemented interceptor as described here to catch the incoming message:
client.getInInterceptors().add(new MyInterceptor());
the class is like the following:
public class MyInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
public MyInterceptor() {
super(Phase.POST_LOGICAL_ENDING);
}
#Override
public void handleMessage(final SoapMessage message) throws Fault {
// Do stuff
}
}
It is on POST_LOGICAL_ENDING phase, but the issue is that handleMessage () is not being called.
We have similar interceptor on outgoing message catching PRE_PROTOCOL_ENDING which works perfectly fine with the service.
What did I miss?
Should I use different phase?
I guess you have to add this interceptor to the out* -> getOutInterceptors()
Background
I have an error message class:
#XmlRootElement
public class ErrorMessage {
private String message;
public ErrorMessage() {
}
public ErrorMessage(String message) {
this.message = message;
}
public String getError() {
return message;
}
public void setError(String message) {
this.message = message;
}
}
This class has been assigned as a return value to an #ExceptionHandler in my Spring MVC REST controller:
#ExceptionHandler
#ResponseStatus(HttpStatus.NOT_FOUND)
#ResponseBody
ErrorMessage handleException(RuntimeException e) {
return new ErrorMessage("something went wrong");
}
Whenever the client triggers a RuntimeException after issuing a request with application/json as a Accept header, it receives a response with the correct status code and a matching JSON body:
{"error":"something went wrong"}
Alternatively, an XML body is received if the Accept header is application/xml:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<errorMessage><error>something went wrong</error></errorMessage>
Problem
Now, I would like to generify this solution by implementing a HandlerExceptionResolver instead so I don't have to copy / paste the #ExceptionHandler to every controller (or create a common "parent controller" that the other controllers can extend).
However, the AbstractHandlerExceptionResolver.doResolveException() method returns a ModelAndView and not my propriety ErrorMessage, so I tried the following:
public class RuntimeExceptionHandlerExceptionResolver extends AbstractHandlerExceptionResolver {
#Override
protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
if (ex instanceof RuntimeException) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
ModelAndView mav = new ModelAndView();
mav.addObject("error", "something went wrong");
return mav;
}
return null;
}
}
When debugging, I can see that the mav.addObject() method is called. The response on the client side has the expected status code, but the content type is text/html with html in the body, rather than the JSON or XLM content that was specified by the Accept header in the original request.
(Side note, the actual exception, response code and text message in the example above is not important, they just serve as simple example.)
Spring version: 3.1.1.RELEASE
To get #ExceptionHandlers to use content negotiation, the AnnotationMethodHandlerExceptionResolver has a setMessageConverters() method which must be provided with the message converters, e.g.:
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver">
<property name="messageConverters">
<list>
<ref bean="xmlConverter"/>
<ref bean="jsonConverter"/>
</list>
</property>
</bean>
But since you're using a custom method, you'll probably have to implement this functionality yourself. The simplest way is probably to Ctrl-C Ctrl-V from the AnnotationMethodHandlerExceptionResolver source, specifically the handleResponseBody() method.
I have spent some time investigating the matter and I have written a blog post in which I present a solution to the problem.
Update: If you are using Spring 3.2, you can take advantage of the #ControllerAdvice annotation. More details can be found in my second blog post.