Skip to content

Commit

Permalink
SIVA-596 Update ValidationExceptionHandler methods
Browse files Browse the repository at this point in the history
  • Loading branch information
ivoMattus committed Jul 9, 2024
1 parent d5361e1 commit 0a95ca7
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.util.MimeType;
import org.springframework.validation.BindingResult;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
Expand All @@ -37,6 +39,12 @@
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;

import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@RestControllerAdvice
public class ValidationExceptionHandler {
Expand Down Expand Up @@ -112,7 +120,8 @@ public RequestValidationError handleNoHandlerFoundException(NoHandlerFoundExcept
@ResponseStatus(value = HttpStatus.METHOD_NOT_ALLOWED)
public RequestValidationError handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
RequestValidationError requestValidationError = new RequestValidationError();
requestValidationError.addFieldError("methodNotAllowed", "Request method " + e.getMethod() + " is not supported");
requestValidationError.addFieldError("methodNotAllowed", "Only the following request methods are supported: "
+ asCommaSeparatedList(e.getSupportedHttpMethods(), HttpMethod::name));
return requestValidationError;
}

Expand All @@ -128,7 +137,8 @@ public RequestValidationError handleHttpMessageNotReadableException(HttpMessageN
@ResponseStatus(value = HttpStatus.UNSUPPORTED_MEDIA_TYPE)
public RequestValidationError handleHttpMediaTypeNotSupportedException(HttpMediaTypeNotSupportedException e) {
RequestValidationError requestValidationError = new RequestValidationError();
requestValidationError.addFieldError("contentTypeNotSupported", "Content-Type " + e.getContentType() + " is not supported");
requestValidationError.addFieldError("contentTypeNotSupported", "Only the following content types are supported: "
+ asCommaSeparatedList(e.getSupportedMediaTypes(), MimeType::toString));
return requestValidationError;
}

Expand All @@ -151,4 +161,13 @@ public void setMessageSource(MessageSource messageSource) {
this.messageSource = messageSource;
}

private static <T> String asCommaSeparatedList(Collection<T> elements, Function<T, String> mapper) {
List<String> mappedElements = Optional
.ofNullable(elements).stream().flatMap(Collection::stream)
.map(mapper)
.collect(Collectors.toList());

return String.join(", ", mappedElements);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -243,29 +243,29 @@ void performPostRequest_WhenEndpointIsInvalid_ThrowsNoHandlerFoundException(Stri

@ParameterizedTest
@MethodSource("provideHttpMethodsAndValidationEndpoints")
void performRequest_WhenEndpointIsSetToValidateOrHashcodeAndHttpMethodIsInvalid_ThrowsHttpRequestMethodNotSupportedException(HttpMethod httpMethod, String endpoint, String requestErrorMessage) throws Exception {
void performRequest_WhenEndpointIsSetToValidateOrHashcodeAndHttpMethodIsInvalid_ThrowsHttpRequestMethodNotSupportedException(HttpMethod httpMethod, String endpoint) throws Exception {
mockMvc.perform(MockMvcRequestBuilders.request(httpMethod, endpoint)
.contentType(MediaType.APPLICATION_JSON)
.content(request().toString().getBytes()))
.andExpect(MockMvcResultMatchers.status().isMethodNotAllowed())
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON))
.andExpect(MockMvcResultMatchers.jsonPath("$.requestErrors", hasSize(1)))
.andExpect(MockMvcResultMatchers.jsonPath("$.requestErrors[0].key", is("methodNotAllowed")))
.andExpect(MockMvcResultMatchers.jsonPath("$.requestErrors[0].message", containsString(requestErrorMessage)))
.andExpect(MockMvcResultMatchers.jsonPath("$.requestErrors[0].message", containsString("Only the following request methods are supported: POST")))
.andReturn();
}

@ParameterizedTest
@MethodSource("provideHttpMethods")
void performRequest_WhenEndpointIsSetToGetDataFilesAndHttpMethodIsInvalid_ThrowsHttpRequestMethodNotSupportedException(HttpMethod httpMethod, String requestErrorMessage) throws Exception {
void performRequest_WhenEndpointIsSetToGetDataFilesAndHttpMethodIsInvalid_ThrowsHttpRequestMethodNotSupportedException(HttpMethod httpMethod) throws Exception {
mockMvcDataFiles.perform(MockMvcRequestBuilders.request(httpMethod, GET_DATA_FILES_URL_TEMPLATE)
.contentType(MediaType.APPLICATION_JSON)
.content(dataFileRequest().toString().getBytes()))
.andExpect(MockMvcResultMatchers.status().isMethodNotAllowed())
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON))
.andExpect(MockMvcResultMatchers.jsonPath("$.requestErrors", hasSize(1)))
.andExpect(MockMvcResultMatchers.jsonPath("$.requestErrors[0].key", is("methodNotAllowed")))
.andExpect(MockMvcResultMatchers.jsonPath("$.requestErrors[0].message", containsString(requestErrorMessage)))
.andExpect(MockMvcResultMatchers.jsonPath("$.requestErrors[0].message", containsString("Only the following request methods are supported: POST")))
.andReturn();
}

Expand Down Expand Up @@ -299,27 +299,27 @@ void performPostRequest_WhenEndpointIsSetToGetDataFilesAndJsonContentIsInvalid_T

@ParameterizedTest
@MethodSource("provideUnsupportedMediaTypesAndValidationEndpoints")
void performPostRequest_WhenEndpointIsSetToValidateOrHashcodeAndContentTypeIsInvalid_ThrowsHttpMediaTypeNotSupportedException(String endpoint, String mediaType, String requestErrorMessage) throws Exception {
void performPostRequest_WhenEndpointIsSetToValidateOrHashcodeAndContentTypeIsInvalid_ThrowsHttpMediaTypeNotSupportedException(String mediaType, String endpoint) throws Exception {
mockMvc.perform(post(endpoint)
.contentType(mediaType)
.content(request().toString().getBytes()))
.andExpect(MockMvcResultMatchers.status().isUnsupportedMediaType())
.andExpect(MockMvcResultMatchers.jsonPath("$.requestErrors", hasSize(1)))
.andExpect(MockMvcResultMatchers.jsonPath("$.requestErrors[0].key", is("contentTypeNotSupported")))
.andExpect(MockMvcResultMatchers.jsonPath("$.requestErrors[0].message", containsString(requestErrorMessage)))
.andExpect(MockMvcResultMatchers.jsonPath("$.requestErrors[0].message", containsString("Only the following content types are supported: application/json, application/*+json")))
.andReturn();
}

@ParameterizedTest
@MethodSource("provideUnsupportedMediaTypes")
void performPostRequest_WhenEndpointIsSetToGetDataFilesAndContentTypeIsInvalid_ThrowsHttpMediaTypeNotSupportedException(String mediaType, String requestErrorMessage) throws Exception {
void performPostRequest_WhenEndpointIsSetToGetDataFilesAndContentTypeIsInvalid_ThrowsHttpMediaTypeNotSupportedException(String mediaType) throws Exception {
mockMvcDataFiles.perform(post(GET_DATA_FILES_URL_TEMPLATE)
.contentType(mediaType)
.content(dataFileRequest().toString().getBytes()))
.andExpect(MockMvcResultMatchers.status().isUnsupportedMediaType())
.andExpect(MockMvcResultMatchers.jsonPath("$.requestErrors", hasSize(1)))
.andExpect(MockMvcResultMatchers.jsonPath("$.requestErrors[0].key", is("contentTypeNotSupported")))
.andExpect(MockMvcResultMatchers.jsonPath("$.requestErrors[0].message", containsString(requestErrorMessage)))
.andExpect(MockMvcResultMatchers.jsonPath("$.requestErrors[0].message", containsString("Only the following content types are supported: application/json, application/*+json")))
.andReturn();
}

Expand Down Expand Up @@ -414,18 +414,18 @@ private JSONObject requestWithInvalidFormatSignatureFile() {
}

private static Stream<Arguments> provideHttpMethodsAndValidationEndpoints() {
return provideValidationEndpoints()
.flatMap(endpoint -> provideHttpMethods()
.map(args -> Arguments.of(args.get()[0], endpoint, "Request method " + ((HttpMethod) args.get()[0]).name() + " is not supported")));
return provideHttpMethods()
.flatMap(httpMethod -> provideValidationEndpoints()
.map(endpoint -> Arguments.of(httpMethod, endpoint)));
}

private static Stream<Arguments> provideHttpMethods() {
private static Stream<HttpMethod> provideHttpMethods() {
return Stream.of(
Arguments.of(HttpMethod.GET, "Request method GET is not supported"),
Arguments.of(HttpMethod.PUT, "Request method PUT is not supported"),
Arguments.of(HttpMethod.DELETE, "Request method DELETE is not supported"),
Arguments.of(HttpMethod.PATCH, "Request method PATCH is not supported"),
Arguments.of(HttpMethod.HEAD, "Request method HEAD is not supported")
HttpMethod.GET,
HttpMethod.PUT,
HttpMethod.DELETE,
HttpMethod.PATCH,
HttpMethod.HEAD
);
}

Expand All @@ -452,29 +452,23 @@ private static Stream<String> provideInvalidJsonContent() {
}

private static Stream<Arguments> provideUnsupportedMediaTypesAndValidationEndpoints() {
return provideValidationEndpoints()
.map(Arguments::of)
.flatMap(endpointArgs -> provideUnsupportedMediaTypes()
.map(mediaTypeArgs -> appendArguments(endpointArgs, mediaTypeArgs)));
return provideUnsupportedMediaTypes()
.flatMap(mediaType -> provideValidationEndpoints()
.map(endpoint -> Arguments.of(mediaType, endpoint)));
}

private static Stream<Arguments> provideUnsupportedMediaTypes() {
private static Stream<String> provideUnsupportedMediaTypes() {
return Stream.of(
Arguments.of(MediaType.APPLICATION_XML_VALUE, "Content-Type application/xml is not supported"),
Arguments.of(MediaType.TEXT_PLAIN_VALUE, "Content-Type text/plain is not supported"),
Arguments.of("application/x-yaml", "Content-Type application/x-yaml is not supported"),
Arguments.of(MediaType.TEXT_HTML_VALUE, "Content-Type text/html is not supported"),
Arguments.of("", "Content-Type application/octet-stream is not supported")
MediaType.APPLICATION_XML_VALUE,
MediaType.TEXT_PLAIN_VALUE,
"application/x-yaml",
MediaType.TEXT_HTML_VALUE,
""
);
}

private static Stream<String> provideValidationEndpoints() {
return Stream.of(VALIDATE_URL_TEMPLATE, HASHCODE_VALIDATION_URL_TEMPLATE);
}

private static Arguments appendArguments(Arguments... arguments) {
return Arguments.of(Stream.of(arguments)
.flatMap(args -> Stream.of(args.get()))
.toArray());
}
}

0 comments on commit 0a95ca7

Please sign in to comment.