Cut Down StackTrace with Interceptor - java

I have web service where i call methods of business service. In one of the methods some kind of exception with appropriate message is thrown. In soap I get exception type and its message (everything is OK). But In log file a bunch of stack trace is written (with detail information). I don't need that. All I need in log file are exception type and its message(like in soap response). But I wouldn't like to change log properties, because of another exceptions must be printed out.
So question is How can I cut down stack trace in log file ?
I've made efforts to solve this problem with #Interceptors annotation bundled on the web method. There my web service method and Interceptor class are shown. Exception is thrown in getLbsLocationForService method .
#WebMethod
#Override
#Interceptors(InterceptionHandleUtil.class)
public LbsLocation getLbsLocationService(#WebParam(name="ms")String ms, #WebParam(name="serID")Long ser) throws ScAccViolation, LbsException {
return serviceProcesses.getLbsLocationForService(ms, ser);
}
Interceptor class :
#Interceptor
public class InterceptionHandleUtil{
#AroundInvoke
public Object intercept(InvocationContext invocationContext) throws Exception {
/*What can I do here to write down in log file just exception type and message*/
return invocationContext.proceed();
}
}

Related

Custom #ControllerAdvice in Spring for exception handling

I am trying to map exceptions from my rest controllers to responses which have a body, and to do it in a central place.
I have tried this:
#Order(Ordered.HIGHEST_PRECEDENCE)
#ControllerAdvice
public class RestErrorResponseExceptionHandler extends ResponseEntityExceptionHandler {
#Override
protected ResponseEntity<Object> handleExceptionInternal(
Exception ex, Object body, HttpHeaders headers, HttpStatus status, WebRequest request) {
super.handleExceptionInternal(ex, body, headers, status, request);
return ResponseEntity.status(status).body(Error.from(status));
}
}
The problem is that the handler is never triggered.
If I define a custom method with #ExceptionHandler in my rest controllers, or extend something that has #ExceptionHandler, then all works well, but that introduces some bad design.
It is my understanding that Spring will first try to look in controller for exception handling methods, then it will check for registered handlers.
I am trying to verify the behaviour via WebMvcTest, and responses I'm getting are not the Error objects that I'm expecting.
Is there something I'm missing?
The ControllerAdvice is a configuration that have to be registered by Spring. You have to move your class in the config package or you can register it by annotation.
In my case, I work with a controllerAdvice like this one :
#ControllerAdvice
public class GlobalControllerExceptionHandler {
#ExceptionHandler(MyException.class)
public ResponseEntity<String> reponseMyException(Exception e) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("my message");
}
}
Spring Framework provides following ways to help us achieving robust exception handling.
Controller Based – We can define exception handler methods in our controller classes. All we need is to annotate these methods with #ExceptionHandler annotation. This annotation takes Exception class as argument. So if we have defined one of these for Exception class, then all the exceptions thrown by our request handler method will have handled.
These exception handler methods are just like other request handler methods and we can build error response and respond with different error page. We can also send JSON error response, that we will look later on in our example.
If there are multiple exception handler methods defined, then handler method that is closest to the Exception class is used. For example, if we have two handler methods defined for IOException and Exception and our request handler method throws IOException, then handler method for IOException will get executed.
Global Exception Handler – Exception Handling is a cross-cutting concern, it should be done for all the pointcuts in our application. We have already looked into Spring AOP and that’s why Spring provides #ControllerAdvice annotation that we can use with any class to define our global exception handler.
The handler methods in Global Controller Advice is same as Controller based exception handler methods and used when controller class is not able to handle the exception.
HandlerExceptionResolver – For generic exceptions, most of the times we serve static pages. Spring Framework provides HandlerExceptionResolver interface that we can implement to create global exception handler. The reason behind this additional way to define global exception handler is that Spring framework also provides default implementation classes that we can define in our spring bean configuration file to get spring framework exception handling benefits.
SimpleMappingExceptionResolver is the default implementation class, it allows us to configure exceptionMappings where we can specify which resource to use for a particular exception. We can also override it to create our own global handler with our application specific changes, such as logging of exception messages.
Make sure of 2 things and your code will work.
Your #ControllerAdvice class is available in component-scan path.
Make sure the methods in your #ControllerAdvice have structure somewhat like this-
#ExceptionHandler(value = { RequestProcessingException.class })
public #ResponseBody ResponseEntity<ErrorMessageBO> hotelConfigServiceExceptionHandler(HttpServletRequest request, RequestProcessingException e) {
logger.error("Exception with tracking Id: {}, dev message: {} and Message:", RequestContextKeeper.getContext().getRequestId(), e.getDeveloperMessage(),e);
return new ResponseEntity<ErrorMessageBO>(new ErrorMessageBO(e.getErrorCode(), e.getMessage(),RequestContextKeeper.getContext().getRequestId(),e.getDeveloperMessage()), HttpStatus.OK);
}

Make #ExceptionHandler handle every exception except AccessDeniedException?

I wrote an #ExceptionHandler to send the exception in JSON for REST requests. However, due to the way Spring Security works, AccessDeniedExceptions must not be handled.
If I simply rethrow an AccessDeniedException in the handler, I get an ERROR level logging saying:
Failed to invoke #ExceptionHandler method: SomeMethod() throws java.lang.Exception
org.springframework.security.access.AccessDeniedException: Access is denied
...Stack...
I cannot safely disable ERROR level logging for the class logging it (ExceptionHandlerExceptionResolver), but having these stacktrace is quite confusing for operations people.
Is there anyway to make #ExceptionHandler not handle this specific exception?
I think you could just use global exception handler instead, so you don't manually handle this AccessDeniedExceptions,
this global exception will be thrown for every kinds of exceptions (except for the exception handlers that you handle manually):
#ControllerAdvice
public class GlobalHandler {
#ExceptionHandler(Exception.class)
public ModelAndView handleException() {
return new ModelAndView("errorGlobal");
}
}

who handles RuntimeException?

I have a class extends HttpServlet contains following two methods. When a client makes a request to web app running on a Tomcat server, http request will be handled via this class however if doSomething method throws RunTimeException how it gets handled based on below example?
protected void doPost(HttpServletRequest reqst, HttpServletResponse resp) {
doSomething();
}
private void doSomething() {
if (false) {
throw new RuntimeException("exception caught calling doSomething method");
}
else {
...
}
}
[update]
Can I add try/catch block inside of doPost where doSomething() is invoked?
All exceptions that reach servlet container code (i.e., those thrown or re-thrown by the doPost() method) will get handled such that Tomcat generates a 500 response, sets Content-Type to text/html, and generates a full HTML page in the body which says that an internal server error has occured, attaching the name and stack trace of the exception.
RE: your [Update]: yes, you can add a try-catch there. In fact, any reasonable implementation will include it. You want your application to dictate what response is sent to your client, not Tomcat or any other container.

Why is java ws rs ExceptionMapper is picking non application exceptions also?

I have a web application in which I throw some custom exceptions(application exceptions annotated with #ApplicationException) and there is an exception mapper(provider annotated with #Provider) for each. Recently I forgot to annotate an exception with #ApplicationException and still the mapper is able to identify the exception and format the response properly.
Then I checked the documentation and I understood that the annotation will be inherited by its child class by default. So I removed the annotation from the super class and checked. The mapper still identified the exception and formatted the response.
Then I went even forward and tried throwing java.lang.IllegalArgumentException and wrote a mapper class for it. It also worked properly. Is javax.ws.rs.ext.ExceptionMapper independent of the exception being thrown. Will it not check if whether thrown exception is really annotated with #ApplicationException?
#Provider
public class IllegalArgumentExceptionMapper implements ExceptionMapper<java.lang.IllegalArgumentException> {
#Override
public Response toResponse(java.lang.IllegalArgumentException exception) {
return Response.status(Status.BAD_REQUEST).entity(exception.getMessage()).build();
}
}
Somewhere in my service class:
throw new java.lang.IllegalArgumentException("Problem with the payload. Please check the payload you are sending");
The answer is no, it will not check if whether thrown exception is really annotated with #ApplicationException.
The exception mapper is independent of the #ApplicationException.
All the exception mapper knows is, if there's no exception caught until the almost last layer, it will be processed here, if it find a matching provider.
You can also actually create a provider for RuntimeException and all exception happened in the REST request will land here (but this is not good practice, we should always throw custom exception and catch them with the provider and convert them to good error response).
When you annotate the exception with #ApplicationException you can control things like whether the transaction should be rollback, and whether it will be wrapped by EJBException etc etc.

NotSerializableException escaping Spring Controller and causing problems with Google App Engine Queue

I have a Spring Controller that is being invoked via an HTTP POST from the GAE Queue Scheduler.
#Controller
#RequestMapping(value = RSSPoller.RSS_POLLER_URL)
public class RSSPoller implements Serializable {
private static final long serialVersionUID = -4925178778477404709L;
public static final String RSS_POLLER_URL = "/rsspoller";
#RequestMapping(method = RequestMethod.POST)
#ResponseStatus(HttpStatus.OK)
public void pollAndProcessRssFeed() throws ServiceException {
try {
// do some stuff
}
catch(Exception e) {
throw new ServiceException("Can't process RSS feed because", e);
}
}
}
However when it gets invoked, the response code is 500 with a Critical log message of
Uncaught exception from servlet
java.lang.RuntimeException: java.io.NotSerializableException: <some spring class that changes all the time, but does not implement java.io.Serializable>
The same log message shows up in the logs with a Warning level as well.
I get similar warning messages (but not critical) in my logs when I invoke other Spring Controllers that either render a web page (GET), or returns some XML data (essentially RPC invokes which use HTTP POST). When I do an HTTP GET/POST to those URLs, the response code is 200 and the output is correct (and I ignore the warning message in the logs).
That leads me to two questions:
Why do I get the Critical error message/HTTP 500 for the POST from the queue, but not the GET/POST to other Spring Controllers in my app?
How can I trap the exception and essentially discard it; as to my purposes the task is complete.
I can post the full exception log if it's of use; for brevity I've omitted it.
you should make your <some spring class that changes all the time, but does not implement java.io.Serializable> just Serializable (not only Controller). Me at least helped it.

Categories