All Downloads are FREE. Search and download functionalities are using the official Maven repository.

me.alidg.errors.handlers.SpringValidationWebErrorHandler Maven / Gradle / Ivy

Go to download

A Spring Boot starter which provides a few primitives to handle exceptions more elegantly.

The newest version!
package me.alidg.errors.handlers;

import me.alidg.errors.Argument;
import me.alidg.errors.HandledException;
import me.alidg.errors.WebErrorHandler;
import org.springframework.beans.TypeMismatchException;
import org.springframework.http.HttpStatus;
import org.springframework.lang.NonNull;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;

import javax.validation.ConstraintViolation;
import java.util.List;
import java.util.Map;

import static java.util.Collections.emptyList;
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toMap;

/**
 * A {@link WebErrorHandler} responsible for handling validation errors thrown by
 * the web layer. Currently, the following exceptions are supported:
 * 
    *
  • {@link BindException}
  • *
  • {@link MethodArgumentNotValidException}
  • *
* * @author Ali Dehghani */ public class SpringValidationWebErrorHandler implements WebErrorHandler { /** * Basic error code for unknown binding errors. */ public static final String BINDING_FAILURE = "binding.failure"; /** * Can only handle supported exceptions mentioned above. * * @param exception The exception to examine. * @return {@code true} if it can handle the exception, {@code false} otherwise. */ @Override public boolean canHandle(Throwable exception) { return exception instanceof MethodArgumentNotValidException || exception instanceof BindException; } /** * After extracting the {@link BindingResult} from the {@code exception}, would iterate over all errors and * pack all validation errors with their corresponding to be exposed arguments. * * @param exception The exception to handle. * @return A {@link HandledException} instance containing the required details about the validation errors. */ @NonNull @Override public HandledException handle(Throwable exception) { BindingResult bindingResult = getBindingResult(exception); return bindingResult.getAllErrors() .stream() .collect(collectingAndThen( toMap(this::errorCode, this::arguments, (value1, value2) -> value1), m -> new HandledException(m.keySet(), HttpStatus.BAD_REQUEST, dropEmptyValues(m)) )); } /** * Extract the {@link BindingResult} from the supported exceptions. * * @param exception The exception to inspect. * @return The extracted {@link BindingResult}. */ private BindingResult getBindingResult(Throwable exception) { return exception instanceof BindingResult ? ((BindingResult) exception) : ((MethodArgumentNotValidException) exception).getBindingResult(); } /** * Extracting the error code from the given {@link ObjectError}. Also, before returning * the error code, would strip the curly braces form the error code, if any (We have our own * message interpolation!). * * @param error Encapsulates the error details. * @return The error code. */ private String errorCode(ObjectError error) { String code = null; try { code = error.unwrap(ConstraintViolation.class).getMessageTemplate(); } catch (Exception ignored) { } if (code == null) { try { code = TypeMismatchWebErrorHandler.getErrorCode(error.unwrap(TypeMismatchException.class)); } catch (Exception ignored) { } } if (code == null) code = BINDING_FAILURE; return code.replace("{", "").replace("}", ""); } /** * Extracts the arguments from the validation meta data and exposes them to the outside * world. First try to unwrap {@link ConstraintViolation} and if successful, use * {@link ConstraintViolationArgumentsExtractor#extract(ConstraintViolation)}. * * @param error Encapsulates the error details. * @return Collection of all arguments for the given {@code error} details. */ private List arguments(ObjectError error) { try { ConstraintViolation violation = error.unwrap(ConstraintViolation.class); return ConstraintViolationArgumentsExtractor.extract(violation); } catch (Exception ignored) { } try { return TypeMismatchWebErrorHandler.getArguments(error.unwrap(TypeMismatchException.class)); } catch (Exception ignored) { } return emptyList(); } /** * Drops the empty collection of arguments! * * @param input The error code to arguments map. * @return The filtered map. */ private Map> dropEmptyValues(Map> input) { return input.entrySet().stream() .filter(e -> e.getValue() != null && !e.getValue().isEmpty()) .collect(toMap(Map.Entry::getKey, Map.Entry::getValue, (v1, v2) -> v2)); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy