【Spring】RestTemplateが投げる例外クラスまとめ

概要

SpringのRestTemplateを使ったAPIコールにおいて、エラー時に投げられる例外クラスの種類をまとめた。
背景としては、SpringのRestTemplateを使っていて、これからエラー時の処理を実装するにあたって必要だと思ったので。

調査方法としては、RestTemplateのソースコードを漁ってみて、例外クラスのjavadocを見たり、実際にthrowされている箇所を見たりしてわかったことをまとめた。

環境

spring-web-4.3.16.RELEASE

例外クラスまとめ

RestTemplateの中には全部で7種類の例外が定義されていた。
それらをクラス図っぽくしてみたのが下記。

RestTemplate (2).png

ひとつずつ見てみる。

RestClientException

javadocは以下

/**
 * Base class for exceptions thrown by {@link RestTemplate} whenever it encounters
 * client-side HTTP errors.
 */
public class RestClientException extends NestedRuntimeException {

RestTemplateの実行において、エラーが発生したときにRestTemplateが投げるベースの例外クラス。
RestTemplateに関する例外全ての親。

RestClientExceptionはNestedRuntimeExceptionを継承しているが、RestTemplateの話からはずれるのでここでは取り上げない。

ResourceAccessException

javadocは以下

/**
 * Exception thrown when an I/O error occurs.
 */
public class ResourceAccessException extends RestClientException {

IO系のエラーが発生したら投げられる例外クラス。
コードを見た感じでは、リクエスト時にIOExceptionが投げられたらcatchしてResourceAccessExceptionをthrowしてるっぽい。

RestClientResponseException

javadocは以下

/**
 * Common base class for exceptions that contain actual HTTP response data.
 */
public class RestClientResponseException extends RestClientException {

HTTPのレスポンスに関する例外を扱うクラス。
どうやら下記で述べるUnknownHTTPStatusCodeExceptionHTTPStatusCodeExceptionに継承されているだけで、このクラスが名指しでthrowされることは無さそうで、だったら抽象クラスでもいいんじゃ?と思いましたが、どうなんでしょう。

UnknownHTTPStatusCodeException

javadocは以下

/**
 * Exception thrown when an unknown (or custom) HTTP status code is received.
 */
public class UnknownHttpStatusCodeException extends RestClientResponseException {

未知のHTTPステータスコードが返されたときに投げられる。
具体的には、返されたステータスコードが、org.springframework.http.HttpStatusのenumで定義されているステータスコード達の中に含まれていなかったら投げられる。

HTTPStatusCodeException

javadocは以下

/**
 * Abstract base class for exceptions based on an {@link HttpStatus}.
 */
public abstract class HttpStatusCodeException extends RestClientResponseException {

HTTPのレスポンスのステータスコードに関するException。
これは抽象クラスで、下記で述べるHTTPServerErrorExceptionHTTPClientErrorExceptionに継承されている。

HTTPServerErrorException

javadocは以下

/**
 * Exception thrown when an HTTP 5xx is received.
 */
public class HttpServerErrorException extends HttpStatusCodeException {

5xx系のステータスコードが返されたときに投げられる。

HTTPClientErrorException

javadocは以下

/**
 * Exception thrown when an HTTP 4xx is received.
 */
public class HttpClientErrorException extends HttpStatusCodeException {

4xx系のステータスコードが返されたときに投げられる。

エラーハンドリングの方針

以上のルールを頭に入れたうえで、catchしたい例外をcatchすればよさそう。
RestTemplateに関する例外を全てcatchしたければ、RestClientExceptionをcatchすればよい。

おまけ:エラー系のステータスコードが返ったときの挙動を少し追ってみる

まずエラーかどうかの判定するのが下記のメソッド
ステータスコードが4xx系, もしくは5xx系だったらtrueが返るみたい
未知のステータスコードの場合、つまりorg.springframework.http.HttpStatusのenumで定義されているステータスコード達の中に含まれていなかったら、getHttpStatusCode()の中でUnknownHTTPStatusCodeExceptionが投げられる。

@Override
public boolean hasError(ClientHttpResponse response) throws IOException {
    try {
        return hasError(getHttpStatusCode(response));
    }
    catch (UnknownHttpStatusCodeException ex) {
        return false;
    }
}

protected boolean hasError(HttpStatus statusCode) {
    return (statusCode.series() == HttpStatus.Series.CLIENT_ERROR ||
                statusCode.series() == HttpStatus.Series.SERVER_ERROR);
}

そして、hasErrorがtrueを返したら呼ばれるのが下記のメソッド。

4xx系の場合はHTTPClientErrorException、5xx系の場合はHTTPServerErrorExceptionが投げられる。

それ以外の場合はRestClientExceptionが投げられるみたいだけど、そもそも未知のステータスコードの場合は, hasError()の時点でgetHttpStatusCodeを呼んだ時点で例外が投げられるのでは?ここが呼ばれることはあるのか?ってなってるのが今。

@Override
public void handleError(ClientHttpResponse response) throws IOException {
    HttpStatus statusCode = getHttpStatusCode(response);
    switch (statusCode.series()) {
        case CLIENT_ERROR:
            throw new HttpClientErrorException(statusCode, response.getStatusText(),
                    response.getHeaders(), getResponseBody(response), getCharset(response));
        case SERVER_ERROR:
            throw new HttpServerErrorException(statusCode, response.getStatusText(),
                    response.getHeaders(), getResponseBody(response), getCharset(response));
        default:
            throw new RestClientException("Unknown status code [" + statusCode + "]");
    }
}
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.