'Issue while getting custom message from @email annotation Spring Boot

I'm trying to get the message from my @Email annotation for my front-end . The issue is that it doesn't actually pass and I get an empty response. Nothing gets passed inside of the response . I just get a 400 bad request in the status in postman but nothing else happens. Each and every other violation of a constraint gives me a json object that contains the custom message that I typed in. I have 3 classes that do this validation I created a CustomExceptionHandler for this :

ApiError.java

import java.util.Arrays;

import java.util.List;

import org.springframework.http.HttpStatus;

public class ApiError {

private HttpStatus status;
private String message;
private List<String> errors;

public ApiError(HttpStatus status, String message, List<String> errors) {
    super();
    this.status = status;
    this.message = message;
    this.errors = errors;
}

public ApiError(HttpStatus status, String message, String error) {
    super();
    this.status = status;
    this.message = message;
    errors = Arrays.asList(error);
}

public HttpStatus getStatus() {
    return status;
}

public void setStatus(HttpStatus status) {
    this.status = status;
}

public String getMessage() {
    return message;
}

public void setMessage(String message) {
    this.message = message;
}

public List<String> getErrors() {
    return errors;
}

public void setErrors(List<String> errors) {
    this.errors = errors;
}

@Override
public String toString() {
    return "ApiError [status=" + status + ", message=" + message + ", errors=" + errors + "]";
}

}

CustomRestHandler.java

import java.util.ArrayList;

import java.util.List;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import 
org.springframework.messaging.handler.annotation.support.MethodArgumentNotValidException;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
 import org.springframework.web.context.request.WebRequest;
 import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
 import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

 import com.neoexams.app.model.ApiError;

 @ControllerAdvice
 public class CustomRestExceptionHandler extends ResponseEntityExceptionHandler 
 {
        
protected ResponseEntity<Object> handleMethodArgumentNotValid(
  MethodArgumentNotValidException ex, 
  HttpHeaders headers, 
  HttpStatus status, 
  WebRequest request) {
    List<String> errors = new ArrayList<String>();
    for (FieldError error : ex.getBindingResult().getFieldErrors()) {
        errors.add(error.getField() + ": " + error.getDefaultMessage());
    }
    for (ObjectError error : ex.getBindingResult().getGlobalErrors()) {
        errors.add(error.getObjectName() + ": " + error.getDefaultMessage());
    }
    
    ApiError apiError = 
      new ApiError(HttpStatus.BAD_REQUEST, ex.getLocalizedMessage(), errors);
    return handleExceptionInternal(
      ex, apiError, headers, apiError.getStatus(), request);
}


@Override
protected ResponseEntity<Object> handleMissingServletRequestParameter(
  MissingServletRequestParameterException ex, HttpHeaders headers, 
  HttpStatus status, WebRequest request) {
    String error = ex.getParameterName() + " parameter is missing";
    
    ApiError apiError = 
      new ApiError(HttpStatus.BAD_REQUEST, ex.getLocalizedMessage(), error);
    return new ResponseEntity<Object>(
      apiError, new HttpHeaders(), apiError.getStatus());
}
  @ExceptionHandler({ ConstraintViolationException.class })
  public ResponseEntity<Object> handleConstraintViolation(
  ConstraintViolationException ex, WebRequest request) 
   {
    List<String> errors = new ArrayList<String>();
    for (ConstraintViolation<?> violation : ex.getConstraintViolations()) {
        errors.add(violation.getMessage());
    }

    ApiError apiError = 
      new ApiError(HttpStatus.BAD_REQUEST, ex.getLocalizedMessage(), errors);
    return new ResponseEntity<Object>(
      apiError, new HttpHeaders(), apiError.getStatus());
}

@ExceptionHandler({ MethodArgumentTypeMismatchException.class })
public ResponseEntity<Object> handleMethodArgumentTypeMismatch(
  MethodArgumentTypeMismatchException ex, WebRequest request) {
    String error = 
      ex.getName() + " should be of type " + ex.getRequiredType().getName();

    ApiError apiError = 
      new ApiError(HttpStatus.BAD_REQUEST, ex.getLocalizedMessage(), error);
    return new ResponseEntity<Object>(
      apiError, new HttpHeaders(), apiError.getStatus());
}

}

User.java

import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

import org.hibernate.annotations.GenericGenerator;

import com.fasterxml.jackson.annotation.JsonIgnore;

@Entity
@Table(name = "users", 
    uniqueConstraints = { 
      @UniqueConstraint(columnNames = "email") 
    })
@DiscriminatorValue(value = "User")
public class User {
  @Id
  @GeneratedValue(generator = "increment")
  @GenericGenerator(name = "increment", strategy = "increment")
  private Long id;

  @NotBlank(message = "Email obligatoire")
  @Size(max = 50,message = "L'email ne doit pas dépasser les 50 caractères")
  @Email(message ="Le format de l'email doit être respecté") 
  private String email;

  @JsonIgnore
  @NotBlank(message = "Mot de passe obligatoire")
  @Size(max=2000, message ="La taille du mot de passe ne doit pas depasser les 2000 caractères")
  private String password;
  
  @NotBlank(message = "Prénom obligatoire")
  private String firstName;
  
  @NotBlank(message = "Nom obligatoire")
  private String lastName;
  @NotEmpty(message ="Rôle obligatoire")
  @ManyToMany(fetch = FetchType.EAGER,cascade = CascadeType.ALL)
  @JoinTable(  name = "user_roles", 
        joinColumns = @JoinColumn(name = "user_id"), 
        inverseJoinColumns = @JoinColumn(name = "role_id"))
  private Set<Role> roles = new HashSet<>();
 
  @NotNull(message = "Activation obligatoire")
  private Boolean enabled;
  
  public User() {
  }

    public User(@NotBlank(message = "Email obligatoire") @Size(max = 50,message = "L'email ne doit pas dépasser les 50 caractères") @Email(message ="Le format de l'email doit être respecté") String email,
            @NotBlank(message = "Mot de passe obligatoire") @Size(max = 2000, message ="La taille du mot de passe ne doit pas depasser les 2000 caractères") String password,
            @NotBlank(message = "Prénom obligatoire") String firstName,
            @NotBlank(message = "Nom obligatoire") String lastName,
            @NotNull(message = "Activation obligatoire") Boolean enabled) {
        super();
        this.email = email;
        this.password = password;
        this.firstName = firstName;
        this.lastName = lastName;
        this.enabled = enabled;
    }

    public User(@NotBlank(message = "Email obligatoire") @Size(max = 50,message = "L'email ne doit pas dépasser les 50 caractères") @Email(message ="Le format de l'email doit être respecté")  String email,
            @NotBlank(message = "Mot de passe obligatoire") @Size(max = 2000, message ="La taille du mot de passe ne doit pas depasser les 2000 caractères") String password) {
        super();
        this.email = email;
        this.password = password;
    }
    
    public User(@NotBlank(message = "Email obligatoire") @Size(max = 50,message = "L'email ne doit pas dépasser les 50 caractères") @Email(message ="Le format de l'email doit être respecté")  String email,
            @NotBlank(message = "Mot de passe obligatoire") @Size(max = 2000, message ="La taille du mot de passe ne doit pas depasser les 2000 caractères") String password, Set<Role> roles) {
        super();
        this.email = email;
        this.password = password;
        this.roles = roles;
    }

    public User(@NotBlank(message = "Email obligatoire") @Size(max = 50,message = "L'email ne doit pas dépasser les 50 caractères") @Email(message ="Le format de l'email doit être respecté") String email,
            @NotBlank(message = "Mot de passe obligatoire") @Size(max = 2000, message ="La taille du mot de passe ne doit pas depasser les 2000 caractères") String password,
            @NotBlank(message = "Prénom obligatoire") String firstName,
            @NotBlank(message = "Nom obligatoire") String lastName,@NotEmpty(message="Rôle obligatoire") Set<Role> roles,
            @NotNull(message = "Activation obligatoire") Boolean enabled) {
        super();
        this.email = email;
        this.password = password;
        this.firstName = firstName;
        this.lastName = lastName;
        this.roles = roles;
        this.enabled = enabled;
    }

public Long getId() {
    return id;
  }

  public void setId(Long id) {  
    this.id = id;
  }


public Boolean getEnabled() {
    return enabled;
}

public String getFirstName() {
    return firstName;
}

public void setFirstName(String firstName) {
    this.firstName = firstName;
}

public String getLastName() {
    return lastName;
}

public void setLastName(String lastName) {
    this.lastName = lastName;
}

public String getEmail() {
    return email;
  }

  public void setEmail(String email) {
    this.email = email;
  }

  public String getPassword() {
    return password;
  }

  public void setPassword(String password) {
    this.password = password;
  }

  public Set<Role> getRoles() {
    return roles;
  }

  public void setEnabled(Boolean enabled) {
    this.enabled = enabled;
}

public void setRoles(Set<Role> roles) {
    this.roles = roles;
  }

}

Every message gets thrown properly from the backend except the email's message



Solution 1:[1]

Try to add an appropriate handler in your @ControllerAdvice

@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public @ResponseBody String handleException(MethodArgumentNotValidException ex) {
  return ex.getMessage();
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 meridbt