Last active
April 19, 2024 15:09
-
-
Save pavelfomin/9906ea08e238ba40ff1f1197925ade57 to your computer and use it in GitHub Desktop.
ControllerExceptionHandler that uses existing org.springframework.http.ProblemDetail for custom exception handling
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.google.api.client.http.HttpHeaders | |
import com.google.api.client.http.HttpResponseException | |
import com.google.cloud.storage.StorageException | |
import org.spockframework.spring.SpringBean | |
import org.springframework.test.web.servlet.ResultActions | |
import static org.hamcrest.Matchers.is | |
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get | |
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print | |
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content | |
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath | |
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status | |
class CloudStorageControllerSpec extends BaseControllerISpec { | |
static final MediaType PROBLEM_JSON_MEDIA_TYPE = new MediaType( | |
MediaType.APPLICATION_PROBLEM_JSON.getType(), MediaType.APPLICATION_PROBLEM_JSON.getSubtype() | |
) | |
@SpringBean | |
CloudStorageService cloudStorageService = Mock() | |
void setup() { | |
0 * _ | |
} | |
def "get storage content by bucket - storage error"() { | |
given: | |
String bucket = "bucket" | |
StorageException exception = new StorageException(404, "not found") | |
when: | |
ResultActions resultActions = mockMvc.perform( | |
get("/storage/{bucket}", bucket) | |
.accept(JSON_MEDIA_TYPE) | |
) | |
then: "exception with a valid HTTP code is thrown" | |
1 * cloudStorageService.list(bucket) >> { throw exception } | |
resultActions | |
.andDo(print()) | |
.andExpect(status().isNotFound()) | |
.andExpect(content().contentType(PROBLEM_JSON_MEDIA_TYPE)) | |
.andExpect(jsonPath('$.title', is("Not Found"))) | |
.andExpect(jsonPath('$.detail', is(exception.message))) | |
.andExpect(jsonPath('$.status', is(exception.code))) | |
when: | |
exception = new StorageException(0, "unknown") | |
resultActions = mockMvc.perform( | |
get("/storage/{bucket}", bucket) | |
.accept(JSON_MEDIA_TYPE) | |
) | |
then: "exception with an invalid HTTP code is thrown" | |
1 * cloudStorageService.list(bucket) >> { throw exception } | |
resultActions | |
.andDo(print()) | |
.andExpect(status().isInternalServerError()) | |
.andExpect(content().contentType(PROBLEM_JSON_MEDIA_TYPE)) | |
.andExpect(jsonPath('$.title', is("Internal Server Error"))) | |
.andExpect(jsonPath('$.detail', is(exception.message))) | |
.andExpect(jsonPath('$.status', is(500))) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.google.api.client.http.HttpResponseException; | |
import com.google.cloud.BaseServiceException; | |
import org.springframework.http.HttpStatus; | |
import org.springframework.http.ProblemDetail; | |
import org.springframework.http.ResponseEntity; | |
import org.springframework.web.bind.annotation.ControllerAdvice; | |
import org.springframework.web.bind.annotation.ExceptionHandler; | |
@ControllerAdvice | |
public class ControllerExceptionHandler { | |
@ExceptionHandler | |
ResponseEntity<?> handleCloudStorageException(BaseServiceException e) { | |
return handleException(HttpStatus.resolve(e.getCode()), e); | |
} | |
@ExceptionHandler | |
ResponseEntity<?> handleHttpResponseException(HttpResponseException e) { | |
return handleException(HttpStatus.resolve(e.getStatusCode()), e); | |
} | |
ResponseEntity<?> handleException(HttpStatus status, Exception e) { | |
if (status == null) { | |
status = HttpStatus.INTERNAL_SERVER_ERROR; | |
} | |
ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(status, e.getMessage()); | |
return new ResponseEntity<>(problemDetail, status); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment