How do you stop spring swallowing exceptions? - java

When something fails on the server side because the database and the application are out of sync instead of getting an error and the application crashing spring/tomcat seems to swallow the exception and pretend nothing has happened.
Call me crazy but if the program fails catastrophically I want it to actually fail catastrophically! Is there anyway to switch this behaviour off? It's really slowing development down when the server pretends that everything is fine when it's just thrown up into the logs.
If this isn't the spring/tomcat default then what else might be causing it?
We are using a boatload of libraries and frameworks unfortunately. Spring would be the usual suspect but it could be something else.
Update
It's a sql server database which we are connecting to using SqlServerDataSource. Hibernate is in use in some parts of the project but is used to query the database at login time. On the client side we are using extjs and we are also using ExtDirectSpring to annotate methods for the client side to talk to. To translate the data going across the wire there's Jackson, which then gets wrapped by the extdirect json handler.
There's some AOP stuff going on thats to do with logging exceptions but deleting that code results in the same behaviour.
Further update
Ok its not a good idea to let your sever crash! See my answer below for my proposed middle ground.

If you really want to do that (but IMHO you should not ...) you can use a filter that will block the application once it let an uncaught exception go. It could be something like :
public class CrashFilter implements Filter {
private boolean crashed = false;
private String msg = "Major problem : application stopped";
#Override
public void doFilter(ServletRequest sr, ServletResponse sr1, FilterChain fc) throws IOException, ServletException {
if (crashed) {
HttpServletResponse resp = (HttpServletResponse) sr1;
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, msg);
return;
}
try {
fc.doFilter(sr, sr1);
}
catch (Exception ex) {
crashed = true;
throw new ServletException(ex);
}
}
// init and destroy omitted from brevity
}

Ok so I did this in the end. I've basically used the ideas above but thought there was enough extra to post my own answer.
It turns out you really shouldn't do this as other people suggested and I've added a bit at the bottom to say why!
Here's my filter:
public class FailOnErrorFilter implements Filter
{
#Override
public void init(FilterConfig config) throws ServletException
{
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException
{
try {
filterChain.doFilter(request, response);
}
catch (Exception exception) {
System.exit(1);
}
}
#Override
public void destroy()
{
}
}
To get this working you have to modify the web.xml:
<filter>
<filter-name>failingFilter</filter-name>
<filter-class>fullyQualified.FailOnErrorFilter</filter-class>
<async-supported>true</async-supported>
</filter>
<filter-mapping>
<filter-name>failingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
The top one defines the filter + the second one says use it everywhere.
ExtDirectSpring
After doing the above I realised that ExtDirectSpring was a further culprit. It's default behaviour is to swallow all exceptions in server side methods.
I was worried I was going to have to patch the library but thankfully someone else had already complained about this and it got fixed in 1.3.6. Initially I tried upgrading to the latest version but it broke a load of code! What a great library. Anyway 1.3.6 added in the ability to switch off the suppression of errors by doing the following:
//this is to switch off blanket switching of exceptions in extdirect spring
#Component
public class NoExceptionHandling implements RouterExceptionHandler
{
#Override
public Object handleException(MethodInfo methodInfo, BaseResponse baseResponse, Exception e, HttpServletRequest httpServletRequest)
{
throw new RuntimeException(e);
}
}
As the name suggests extdirectspring uses spring and so doesn't make its dependencies obvious to calling code, however if you go digging (its on github). You'll see in RouterController it calls the following method in the catch
private Object handleException(MethodInfo methodInfo, BaseResponse response, Exception e, HttpServletRequest request) {
return configurationService.getRouterExceptionHandler().handleException(methodInfo, response, e, request);
}
Where router controller does this:
#Autowired(required = false)
private RouterExceptionHandler routerExceptionHandler;
public RouterExceptionHandler getRouterExceptionHandler() {
return routerExceptionHandler;
}
It sets up a default one if you dont provide one.
Update - why you shouldn't do this
It turns out you really shouldn't call System.exit in a tomcat application. Not only does it bring down your application it also causes the server to exit. This brings down any other applications running aswell!
It's also not appropriate for a number of other reasons:
if the first in a series of tests throws an exception then all subsequent tests will fail
Its time consuming restarting the server and you have to be the person who breaks it to see the exception
if you are running a manual test deployment on a seperate machine then you have to restart the server if something caused a problem somewhere.
Likewise:
In production it will take everyone's application down and most users wont be in a position to restart the server.
What I'm doing instead
The errors were already being written the the tomcat logs + the database.
In debug we now also going to redirect to an error page with the stacktrace
In production we are going to just redirect to a 'something went wrong' page. We're also going to set up an email service that notifies us of exceptions.
For UI/selenium tests - it'll work the same as debug
For headless Js tests the server rejects subsequent requests until the next test resets the error state of the server
Just to make things more complicated unsurprisingly the original webapp is too flaky to not mask errors so I've kept the old error suppression in place for that as we're not actively developing/fixing it at the moment.

Related

How do I change only the status code on a Spring MVC error with Boot?

I'm writing a Web application that makes downstream calls using RestTemplate. If the underlying service returns a 401 Unauthorized, I want to also return a 401 to the calling application; the default behavior is to return a 500. I want to keep the default Spring Boot error response as provided by BasicErrorController; the only change I want is to set the status code.
In custom exceptions, I'd just annotate the exception class with #ResponseStatus, but I can't do that here because HttpClientErrorException.Unauthorized is provided by Spring. I tried two approaches with #ControllerAdvice:
#ExceptionHandler(HttpClientErrorException.Unauthorized.class)
#ResponseStatus(UNAUTHORIZED)
public void returnsEmptyBody(HttpClientErrorException.Unauthorized ex) {
}
#ExceptionHandler(HttpClientErrorException.Unauthorized.class)
#ResponseStatus(UNAUTHORIZED)
public void doesNotUseBasicErrorController(HttpClientErrorException.Unauthorized ex) {
throw new RuntimeException(ex);
}
How can I configure MVC to continue to use all of the built-in Boot error handling except for explicitly overriding the status code?
The below code works for me -- in an app consisting of a #RestController whose one method consisted of throw new HttpClientException(HttpStatus.UNAUTHORIZED), running on an embedded Tomcat. If you're running on a non-embedded Tomcat (or, I suspect, on an embedded non-Tomcat) odds are you'll have to do something at least somewhat different, but I hope this answer is at least somewhat helpful anyway.
#ControllerAdvice
public class Advisor {
#ExceptionHandler(HttpClientException.class)
public String handleUnauthorizedFromApi(HttpClientException ex, HttpServletRequest req) {
if (/* ex instanceof HttpClientException.Unauthorized or whatever */) {
req.setAttribute(RequestDispatcher.ERROR_STATUS_CODE, 401);
}
return "forward:/error";
}
}
Explanation: when a HttpClientException is thrown while we're processing request X (in an embedded servlet), what normally happens is that it bubbles all the way up to some org.apache class. (I might fire the debugger up again and work out which one, but this is a pretty high-level explanation so it doesn't matter much.) That class then sends request X back to the application, except this time the request goes to "/error", not to wherever it was originally going. In a Spring Boot app (as long as you don't turn some autoconfiguration off), that means that request X is ultimately processed by some method in BasicErrorController.
OK, so why does this whole system send a 500 to the client unless we do something? Because that org.apache class mentioned above sets something on request X which says "processing this went wrong". It is right to do so: processing request X did, after all, result in an exception which the servlet container had to catch. As far as the container is concerned, the app messed up.
So we want to do a couple of things. First, we want the servlet container to not think we messed up. We achieve this by telling Spring to catch the exception before it reaches the container, ie by writing an #ExceptionHandler method. Second, we want the request to go to "/error" even though we caught the exception. We achieve this by the simple method of sending it there ourselves, via a forward. Third, we want the BasicErrorController to set the correct status and message on the response it sends. It turns out that BasicErrorController (working in tandem with its immediate superclass) looks at an attribute on the request to determine what status code to send to the client. (Figuring this out requires reading the class's source code, but that source code is on github and perfectly readable.) We therefore set that attribute.
EDIT: I got a bit carried away writing this and forgot to mention that I don't think using this code is good practice. It ties you to some implementation details of BasicErrorController, and it's just not the way that the Boot classes are expected to be used. Spring Boot generally assumes that you want it to handle your error completely or not at all; this is a reasonable assumption, too, since piecemeal error handling is generally not a great idea. My recommendation to you -- even if the code above (or something like it) does wind up working -- is to write an #ExceptionHandler that handles the error completely, meaning it sets both status and response body and doesn't forward to anything.
You can customize the error handler of the RestTemplate to throw your custom exception, and then handle that exception with the #ControllerAdvice as you mentioned.
Something like this:
#Configuration
public class RestConfig {
#Bean
public RestTemplate restTemplate(){
// Build rest template
RestTemplate res = new RestTemplate();
res.setErrorHandler(new MyResponseErrorHandler());
return res;
}
private class MyResponseErrorHandler extends DefaultResponseErrorHandler {
#Override
public void handleError(ClientHttpResponse response) throws IOException {
if (HttpStatus.UNAUTHORIZED.equals(response.getStatusCode())) {
// Throw your custom exception here
}
}
}
}

Distinguish requests between multiple connectors/ports in embedded Tomcat in Spring Boot

I have a Spring Boot rest service based application configured on multiple ports that needs to distinguish each request between the port it came through. The idea of having several ports for the application is due to different public and private sub-networks (with different security access levels) that could access different parts of the services exposed by the application.
Conceptually the idea was to add additional connectors to the embedded tomcat and then catch all incoming requests altering them by adding a custom header to each one specifying the "channel" it came through.
The problem I'm facing is that I have no idea how I could catch these incoming requests on a connector level (before it gets to any filter or servlet).
So, for the multi-port solution I have:
#Configuration
public class EmbeddedTomcatConfiguration {
#Value("${server.additional-ports}")
private String additionalPorts;
#Bean
public TomcatServletWebServerFactory servletContainer() {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
Connector[] additionalConnectors = additionalConnector();
if(additionalConnectors != null && additionalConnectors.length > 0) {
tomcat.addAdditionalTomcatConnectors(additionalConnectors);
}
return tomcat;
}
private Connector[] additionalConnector() {
if(StringUtils.isNotBlank(additionalPorts)) {
return Arrays.stream(additionalPorts.split(","))
.map(String::trim)
.map(p -> {
Connector connector = new Connector(Http11NioProtocol.class.getCanonicalName());
connector.setScheme("http");
connector.setPort(Integer.valueOf(p));
return connector;
})
.toArray(Connector[]::new);
}
return null;
}
}
In theory, I could register a custom LifecycleListener to each connector, but, as far as I know, it won't help. I've also heard something about valves, though I'm not sure how to implement them per connector.
Or maybe I'm going a completely wrong way.
I'd really appreciate any help in the matter.
It seems as though you have your heart set on trying a Valve, but, after some more research, I would recommend using a ServletFilter to do this work instead of a Valve.
I believe you can do this work in a Valve, but a Valve must be deployed into the tomcat/lib directory instead of being packaged inside of your application. I would urge you to consider trying to keep your application together in deployable artifact instead of having to remember to deploy one extra jar file to your tomcat instance when creating a new deployment.
From this answer, Difference between getLocalPort() and getServerPort() in servlets you should be able to access the tomcat port by calling getLocalPort() on the HttpServletRequest.
Then based on your idea in the question add a specific context name into the request header.
public class PortContextFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
int localPort = request.getLocalPort();
// if else or case statements
ServletRequest newRequest = PortContextHttpServletRequestWrapper(request, YourPortContext)
filterChain.doFilter(newRequest, response);
}
public void destroy() {
// Nothing to do
}
public void init(FilterConfig filterConfig) throws ServletException {
// Nothing to do.
}
}
After that is done, in theory, you should be able to use the #RequestMapping annotation to route based on the name inside the header.
#PreAuthorize("hasPermission(#your_object, 'YOUR_OBJECT_WRITE')")
#RequestMapping("/yourobject/{identifier}", headers="context=<context_name>", method = RequestMethod.POST)
public String postYourObject(#PathVariable(value = "identifier") YourObject yourObject) {
// Do something here...
...
}
One can also use RequestCondition to route requests based on port, which I think is closer to stock spring. see Spring Boot | How to dynamically add new tomcat connector?

Enforce QoS metrics on Java methods via timeouts in Jersey server

In perfect world, I would imagine that there is an annotation like #QoS(10, CONSTANT_RETURN_OBJECT) which can be placed around java methods and if they take longer than the specified time (10 seconds in this example) to execute then the method execution is essentially considered timed out and we return a pre-packaged CONSTANT_RETURN_OBJECT defined by the developer to indicate empty results.
But realistically, what is a good approach supported by or recommended for enforcing how long a jersey-server method can run for before we say its too darn long and just return and go on our merry way?
And its a given (for my question here) that you have no control over the client side that is calling jersey-server so you can NOT go set a timeout there ... which is why you are enforcing some reasonable ones on the server side.
UPDATE:
I guess what I am asking to some degree is if there is an annotation that would essentially wrap a method call as an Executor driven task and run it with a timeout? Sort of like what the code written in the answers for these two posts does:
How to set a timer in java
How do I call some blocking method with a timeout in Java?
The way to do this would be to implement a servlet filter. A basic filter looks like this:
public class TimeoutFilter implements Filter {
#Override
public void doFilter(final ServletRequest servletRequest,
final ServletResponse servletResponse,
final FilterChain chain) throws IOException, ServletException {
final HttpServletRequest req = (HttpServletRequest)servletRequest;
try {
// Execute this with a time limit
chain.doFilter(servletRequest, servletResponse);
}
catch (Exception e) {
// Handle exceptions here; you should state the exceptions explicitly
// rather than just catching Exception
}
}
}
You can then set up an Executor or whatever in the filter to provide a time limit for the request.

Is it any way to display custom 500-errors on App Engine (GAE)?

Server errors result in HTTP 500-responses to the client with a generic error message ("The server encountered an error..."). Is there any way to intercept this message and write a custom one?
I'm would like to have a way to uniquely identify a server error from the client. If I could for instance generate a GUID which I logged server-side upon a server error and then send that ID to the client, that would make it easy to search for that particular exception in the log at any point later in time.
I do realize that server errors are generated by exceptions in the code, so I'm looking for some kind of catch all exception hook in the app engine API. Of course, if such a hook exists, and the code which executes here generates a second exception, it would have to default to the general 500-error again.
I'm using the Java API for GAE
For GAE generated errors you can configure a custom error page. For errors generated by your code you should use a catch-all wrapper inside a first servlet filter.
I ended up coding a Servlet Filter by following the answer in this SO question. The filter wraps the doFilter() call in a general try-catch block and creates a reference number for the client while logging it at the server. I think this little snippet might be useful for others out there:
public class ExceptionFilter implements Filter {
private FilterConfig filterConfig;
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws IOException, ServletException {
try {
filterChain.doFilter(request, response);
}
catch (Exception ex) {
String errorId = UUID.randomUUID().toString();
Mylog.e("Server error " + errorId); // Use whatever logging mechanizm you prefer
String clientResponse = "Server error. Reference no: " + errorId;
((HttpServletResponse) response).setStatus(500);
response.getWriter().write(clientResponse);
}
}
public FilterConfig getFilterConfig() {
return filterConfig;
}
public void init(FilterConfig filterConfig) {
this.filterConfig = filterConfig;
}
public void destroy() {}
}
You also need to configure web.xml like this (goes somewhere under the <web app> tag):
<filter>
<filter-name>ExceptionFilter</filter-name>
<filter-class>your.package.ExceptionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ExceptionFilter</filter-name>
<servlet-name>Your Servlet Name As Defined In servlet-mapping</servlet-name>
</filter-mapping>
You didn't mention if your using python or java. Python error display https://developers.google.com/appengine/docs/python/config/appconfig#Custom_Error_Responses
Note these are just static pages that are shown in the event of any uncaught errors.
You can try and catch these errors in your main handler (I am talking about python), but you can't always. For instance you maybe able to catch a DeadlineExceededError some times, and you may have a tiny bit of time to emit a log, or a redirect (maybe to the same page to try again or to your own static page, with an arg with the GUID you mentioned, then have javascript render it some useful way) but often that won't work. So it very much depends on the nature of the error.

Java doFilter() throws NPE as part of a superclass

Okay - I've been doing some work with Java filters at work lately, and we often have to recycle code when moving between web apps; we can make the filters look at a relative location so that they can be used across multiple contexts, but we still go through a lot of them. So, I've created a superclass to aid in code production; I also added the runFilter method as an abstract method in the superclass, just to keep it separate from the standard doFilter. The superclass code looks like this:
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
try {
runFilter(req,resp,chain);
}
catch (Exception e) {
getLogger().error("Error! Exception:",e);
}
}
Now, here's the problem: whenever a filter extending the above code triggers, I get errors like I set up in the logger above, but I also get the logger messages from inside the child class's runFilter indicating that it's doing its job - the forwarding even works as it ought. I look at my console, and it's showing errors occurring on the lines where the child class is accessing the filter chain.
if (isExcluded(debugURI)) {
chain.doFilter(request, response);
return;
} else if (request.getSession().getAttribute("USER") == null) {
getLogger().info("Session with ID " + serialVersionUID + " has timed out. Redirecting to " + getRedirectTarget() + ".");
response.sendRedirect(getRedirectTarget());
chain.doFilter(request, response);
return;
}
else {
chain.doFilter(request, response);
return;
}
Does the FilterChain need to be updated (or extended) in order to receive a call for runFilter, as well? Any help would be very useful.
I stumbled across this error very early in my work with servlets; the problem is quite simple, actually. I had errors being generated from within the superclass because each filter instantiation failed at a fundamental level; however, the real blunder was my attempt to call the doFilter method after a sendRedirect - since the sendRedirect method terminates the chain, I was attempting to access a stub. Any redirection needs to be handled within the filter chain, because a sendRedirect terminates it.

Categories