com.naharoo.commons.mstoolkit.rest.exceptionhandler.HttpMessageNotReadableExceptionHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ms-toolkit-rest-exception-handler-starter Show documentation
Show all versions of ms-toolkit-rest-exception-handler-starter Show documentation
Common exceptions handler as a Spring Boot Starter
package com.naharoo.commons.mstoolkit.rest.exceptionhandler;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import com.naharoo.commons.mstoolkit.exceptions.CommonIssueType;
import com.naharoo.commons.mstoolkit.exceptions.IssueType;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static java.lang.String.format;
import static java.util.Collections.singleton;
import static java.util.Collections.singletonList;
import static java.util.Objects.isNull;
import static java.util.regex.Pattern.compile;
@ControllerAdvice
@ConditionalOnProperty(prefix = "ms-toolkit.rest-exception-handler.handlers.enabled", name = "NOT_READABLE_REQUEST_BODY", havingValue = "true", matchIfMissing = true)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnClass(name = "org.springframework.http.converter.HttpMessageNotReadableException")
public class HttpMessageNotReadableExceptionHandler extends AbstractExceptionHandler {
public static final String ENUM_FAIL_ON_NUMBERS_MSG = "Numeric value for Enum not supported.";
private static final Pattern ENUM_MSG_PATTERN =
compile("(.*)\\.(.*)` from String \"(.*)(\": not one of the values accepted for Enum class: )(.*)");
private static final String ENUM_ERROR_MSG = "%s: invalid value '%s' should be one of %s";
private static final String ERROR_MSG = "%s: %s";
private static final Pattern ENUM_FAIL_ON_NUMBERS_PATTERN = compile(
"^.*FAIL_ON_NUMBERS_FOR_ENUMS.*$",
Pattern.DOTALL
);
/**
* Handle HttpMessageNotReadableException. Thrown when request body is malformed.
*/
@ExceptionHandler(HttpMessageNotReadableException.class)
public ResponseEntity> handle(
final HttpMessageNotReadableException exception,
final HttpServletRequest request
) {
final HttpServletRequestInfoBuilder infoBuilder = HttpServletRequestInfoBuilder.newInstance(
request);
logTrace(exception, infoBuilder);
final IssueType type = CommonIssueType.NOT_READABLE_REQUEST_BODY;
final int statusCode = type.statusCode();
final ResponseEntity response = ResponseEntity
.status(statusCode)
.body(new ApiErrorResponse(
statusCode,
singleton(type),
singletonList(buildErrorMessage(exception)),
LocalDateTime.now()
));
logInfo(exception, infoBuilder);
return response;
}
private String buildErrorMessage(final HttpMessageNotReadableException exception) {
final Throwable cause = exception.getCause();
if (isNull(cause)) {
return exception.getLocalizedMessage();
}
if (cause instanceof InvalidFormatException) {
return this.buildInvalidFormatExceptionMessage((InvalidFormatException) cause);
} else if (cause instanceof JsonProcessingException) {
return ((JsonProcessingException) cause).getOriginalMessage();
} else {
return exception.getLocalizedMessage();
}
}
private String buildInvalidFormatExceptionMessage(
final InvalidFormatException invalidFormatException
) {
String errorMessage = null;
final String path = buildPath(invalidFormatException.getPath());
final String invalidFormatExceptionMessage = invalidFormatException.getMessage();
if (!isNull(invalidFormatExceptionMessage)) {
if (ENUM_FAIL_ON_NUMBERS_PATTERN.matcher(invalidFormatExceptionMessage).matches()) {
return format(ERROR_MSG, path, ENUM_FAIL_ON_NUMBERS_MSG);
}
final String[] exceptionMessageLines = invalidFormatExceptionMessage.split("\n");
if (exceptionMessageLines.length > 1) {
final Matcher enumErrorMsgMatcher = ENUM_MSG_PATTERN.matcher(exceptionMessageLines[0]);
if (enumErrorMsgMatcher.matches()) {
final String invalidValue = enumErrorMsgMatcher.group(3);
final String possibleValues = enumErrorMsgMatcher.group(5);
errorMessage = format(ENUM_ERROR_MSG, path, invalidValue, possibleValues);
} else {
errorMessage = format(ERROR_MSG, path, exceptionMessageLines[0]);
}
}
}
return errorMessage;
}
private String buildPath(final List pathReference) {
final StringBuilder path = new StringBuilder();
pathReference.forEach(
reference -> {
if (reference.getIndex() > -1) {
path.append("[").append(reference.getIndex()).append("]");
} else {
if (path.length() > 0) {
path.append(".");
}
path.append(reference.getFieldName());
}
});
return path.toString();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy