DefaultResponseErrorHandler
を設定するしないでステータスコードの取得方法が変わる
答えはここにあったけど、見逃していた
環境
Java : 11
JUnit : 4.12
Spring Boot : 2.1.6
設定するしないに関わらない共通のサンプルコード
SandboxApplication.java
@SpringBootApplication
public class SandboxApplication {
public static void main(String[] args) {
SpringApplication.run(SandboxApplication.class, args);
}
// 雑にここでBean登録
@Bean
public RestTemplate setRestTemplate(){
return new RestTemplate();
}
}
Hoge.java
class Hoge {
String message;
public Hoge(@JsonProperty("message") String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}
SampleTest.java
@RunWith(SpringRunner.class)
@SpringBootTest
public class SampleTest {
@Autowired
RestTemplate restTemplate;
@Autowired
ObjectMapper objectMapper;
@Autowired
Sample sut;
@Test
public void テストだよ() throws Exception {
// 2xx系 : ex) OK
setUpMockRestServer(HttpStatus.OK);
assertThat(sut.getHoge().getMessage(), is("200だよ"));
// 4xx系エラー : ex) NOT_FOUND
setUpMockRestServer(HttpStatus.NOT_FOUND);
assertThat(sut.getHoge().getMessage(), is("404だよ"));
// 5xx系エラー : ex) INTERNAL_SERVER_ERROR
setUpMockRestServer(HttpStatus.INTERNAL_SERVER_ERROR);
assertThat(sut.getHoge().getMessage(), is("500だよ"));
}
private void setUpMockRestServer(HttpStatus status) throws JsonProcessingException {
MockRestServiceServer mockServer = MockRestServiceServer.bindTo(restTemplate).ignoreExpectOrder(true).build();
String response = objectMapper.writeValueAsString(new Hoge(status.value() + "だよ"));
mockServer.expect(requestTo("https://hoges/1"))
.andRespond(withStatus(status).body(response).contentType(MediaType.APPLICATION_JSON_UTF8));
}
}
DefaultResponseErrorHandlerを設定しない
- クライアントエラー系(4xx)の場合、
HttpClientErrorException
- サーバエラー系(5xx)の場合、
HttpServerErrorException
- 自身で設定したコードの場合、
UnknownHttpStatusCodeException
上記をそれぞれtry-catch
で扱う必要がある
Sample.java
@Component
public class Sample {
RestTemplate restTemplate;
public Sample(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public Hoge getHoge() {
ResponseEntity<Hoge> response;
try {
response = restTemplate.getForEntity("https://hoges/1", Hoge.class);
} catch (HttpClientErrorException | HttpServerErrorException e) {
// statusCodeによって分岐できる
int statusCode = e.getStatusCode().value();
return new Hoge(statusCode + "だよ");
}
return response.getBody();
}
}
DefaultResponseErrorHandlerを設定する
DefaultResponseErrorHandler
を継承して、余計なことすんなという設定をすることで実現できる
SampleResponseErrorHandler.java
@Component
public class SampleResponseErrorHandler extends DefaultResponseErrorHandler {
@Override
public void handleError(ClientHttpResponse response) throws IOException {
// 何も書かないことで、サーバーエラーとクライアントエラーが起きても例外を発生させない
}
}
Sample.java
@Component
public class Sample {
RestTemplate restTemplate;
SampleResponseErrorHandler sampleResponseErrorHandler;
public Sample(RestTemplate restTemplate, SampleResponseErrorHandler sampleResponseErrorHandler) {
this.restTemplate = restTemplate;
this.sampleResponseErrorHandler = sampleResponseErrorHandler;
}
public Hoge getHoge() {
// 独自定義したErrorHandlerをRestTemplateに設定しておく
restTemplate.setErrorHandler(sampleResponseErrorHandler);
ResponseEntity<Hoge> response = restTemplate.getForEntity("https://hoges/1", Hoge.class);
// サンプルではそのままreturnしているけど、ここでResponseEntityから取得できるステータスコードでいくらでも分岐できちゃう
return response.getBody();
}
}
まとめ
ステータスコード取得して詳細に分岐したいのに、例外で拾えないよーってハマって辛かった。