6

Oracle summarises the purpose of unchecked exceptions as:

The next question might be: "If it's so good to document a method's API, including the exceptions it can throw, why not specify runtime exceptions too?" Runtime exceptions represent problems that are the result of a programming problem, and as such, the API client code cannot reasonably be expected to recover from them or to handle them in any way. Such problems include arithmetic exceptions, such as dividing by zero; pointer exceptions, such as trying to access an object through a null reference; and indexing exceptions, such as attempting to access an array element through an index that is too large or too small.

Ok, so unchecked exceptions are for any errors caused by programmer error. Sure.

Spring's documentation for the HttpClientErrorException (which extends RuntimeException) says the exception is for:

Exception thrown when an HTTP 4xx is received.

I can't see that this is a 'programmer error' exception.

In the scenario I'm testing, I'm making a query to a Spring RestTemplate, but the server it's querying may be down, and return a 404. This seems like a perfectly normal state of affairs, not a programming error.

Am I perhaps interacting with the Spring Framework incorrectly (ie. I should be detecting the 404 before using the RestTemplate?) or is there something else I'm not considering?

1
  • 2
    Spring and several other important Java libraries simply have taken the stance that checked exceptions were a design mistake in the language, and therefore exclusively use unchecked exceptions for everything. I was absolutely sure there used to be a rationale for that in the Spring docs, but I can't find it anymore. May 17, 2018 at 8:19

4 Answers 4

6

I think you are doing well.

See it from this point of view. Unchecked Exceptions - Controversy.

If a client can reasonably be expected to recover from an exception, make it a checked exception. If a client cannot do anything to recover from the exception, make it an unchecked exception.

It's a handicap due to the above premise. Spring Rest Client doesn't expect to recover itself from a 404 so it delegates the decision of handling the error to upper layers.

It's your system's responsibility to decide what to do with 4xx or 5xx errors. The way to don't compromise the whole Spring Web and core architecture with useless try/catch/final blocks and refactor countless components adding the throw to signatures is typing exceptions asRuntimeExceptions.

In consequence, Spring user is involved in such eventuality. Spring delegate to us to take care and recover from these errors, or let them go (like they do) up to the next layers... And so on...

To your question

ie. Should I be detecting the 404 before using the RestTemplate?

It depends on what you need to do when the integration fails. I would suggest taking a look to fault tolerance patterns such as Circuit Breaker. This is a fairly known one, but there're more. Some times, the best you can do is let the exception go.

Finally, worth mention Spring's ErrorHandlers what let you handle errors in a more greaceful way. You can overwrite the method handleResponse too.

4

No one got to the root of the problem. In spring-web, this is fine. The problem is that Spring Rest uses it, too. The purpose of the two are very different.

When spring-web is doing it's thing to serve up my paths, that's great! I'll use the ControllerAdvice and what-not to handle those exceptions properly before sending a response to my user.

However, when using rest client to make my own requests to a 3rd party site, I could be inside an Async task, where there is no user to display the ControllerAdvice response to. Even if there is a user, I'd want to give them something better than my local spring's exception handler (like integrate it into the form they submitted). This is not unreasonable. This is not rare. So, why does spring rest not provide a more intuitive and expected error handler?

The root of the problem is the interdependence of these 2, when they have completely different purposes in the life-cycle of a spring app. Having to ALWAYS override the error handling when using it from spring rest is not acceptable.

If that's the case, I would catch HttpClientErrorException.

This is not acceptable, as you may not even know that you can until the problem shows up. Checked exceptions alert the developer they need to do something. Hiding them behind Runtime exceptions removes this helpful alert and discourages proactive error handling. It's removing knowledge from the developer. I can't see that as a good thing, in any context. This is one of the main problems with humans - we tend to find, accept, and propagate workarounds much more than we are willing to actually make things better.

Snide Remark: Why doesn't HttpClient do it? They work with the Apache guys. I think I'd trust them over Oracle, Spring, or StackExchange randos any day.

Eh, what do I care. I've been using http client for a decade...

0

I am assuming that Spring considered 404 an "unrecoverable" scenario.

I believe that the concept of "recovering from a 404" is not in-line with what Oracle meant with "recoverable".

Oracle's "unrecoverable" means that shit went seriously wrong. As in NullPointerException, or similar. As in a bug in the source code. That's where unchecked exceptions come in play.

My understanding is that all HTTP codes are considered a valid scenario of the HTTP spec. They are documented, expected, and have known mitigations.

I'm afraid that Spring is on the wrong side of this.

For instance RestTemplate#doExecute, wraps the http client's checked exception in an unchecked exception. This is bad...


I am currently facing a very similar problem.

I need to write a custom ResponseErrorHandler that throws some very specific exceptions (that could extend IOException, because it's in the interface's signature).

Then RestTemplate hides this by wrapping the IOException in an unchecked exception.

It would be nice of Spring to give an explanation, or if there is none, fix this.

1
  • 1
    "the API client code cannot reasonably be expected to recover from them or to handle them in any way" The thing about HTTP 4xx errors is the CLIENT can't do anything but retry. Also consider: "Having to add runtime exceptions in every method declaration would reduce a program's clarity. Thus, the compiler does not require that you catch or specify runtime exceptions (although you can)." HTTP errors occur a LOT, and can bubble up in many places. Perhaps the designers felt Client Exception was like Null Pointer Exceptions, and better done as an unchecked.
    – Kristian H
    Oct 15, 2016 at 5:13
0

HTTP 4xx return codes denote that the request itself is invalid, the fault lies with the client - as opposed to HTTP 5xx which denote server-errors while responding to a otherwise valid request.

Understood this way, it is perfectly reasonable to consider HTTP 4xx return codes to be programming errors and unrecoverable. After all, if the client knew how to send valid requests, why didn't it do that in the first place? 404 specifically means "We looked for the resource you wanted, but we ain't found shit". To request something that does not exist is an invalid request from a certain point of view and that can absolute be a programming error. Someone could have typed in the wrong URL into the code/config file/.... Now, it could also be an expected behaviour if the resource at that URL is supposed to be optional. It depends on the specific request and the specific API. How is Spring supposed to know which is which?

Another point altogether: If the server is unavailable, it won't send you an 404. It won't respond at all. At the most it can respond with 503 if it is under too much load, but that's about it. If the server is down, it won't respond at all. An intermediate gateway-service may respond in its stead, but even that shouldn't use 404. It should use 504 in this case.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.