Skip to content
Advertisement

spring boot starter validation simply not working

Problem:

I need to validate some json inputs and outputs in my Spring API, I’m trying to use spring boot starter validation (Already know that is not into spring-boot-starter-web, so I added it manually) but it never throws the exception when something is bad based on the validations in the DTO class (MethodArgumentNotValidException)

Complete project can be fonud on github

What I’ve tried:

  1. I tried adding this 3 dependencies:

    <dependency>
        <groupId>javax.validation</groupId>
        <artifactId>validation-api</artifactId>
        <version>2.0.1.Final</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate.validator</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>6.0.13.Final</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish</groupId>
        <artifactId>javax.el</artifactId>
        <version>3.0.0</version>
    </dependency>
    

    And is not working, I’m able to send incorrect values without throwing the exception

    P.S. I already know that spring boot starter validation is not into spring-boot-starter-web, so I added it manually

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>
    

    If I try to use spring-boot-starter-validation without the validation-api (from javax) it directly says that some methods do not exists (Like @Valid or @Max or @Min)

  2. Already Rebuild project

  3. Already clean maven repository and installed again

What I have:

DTOs:

import lombok.*;


import javax.validation.Valid;
import javax.validation.constraints.*;
import java.util.List;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class StudentDTO {
    @NotEmpty(message = "Username cant be empty")
    @Size(min = 2, max = 50, message = "Minimum 2 letters, max 50")
    String studentName;
    String message;
    Double averageScore;
    List<@Valid SubjectDTO> subjects;
}
import lombok.*;

import javax.validation.constraints.*;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class SubjectDTO {
   @NotEmpty(message = "Subject name cant be empty")
   @Size(max = 30, message = "Max 30 letters")
   @Pattern(regexp = "[A-Z](\p{L}||\s)+", message = "Name should start with capital letter")
   String name;
   @Max(value = 10, message = "Max grade is 10.0")
   @Min(value = 0, message = "Min grade is 0.0")
   Double score;
}

import lombok.*;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ErrorDTO {
   private String name;
   private String description;
}

Rest controller:

import com.practicastesting.diploma.dto.StudentDTO;
import com.practicastesting.diploma.service.IObtenerDiplomaService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;

@RestController
public class ObtenerDiplomaController {
   @Autowired
   IObtenerDiplomaService service;

   @PostMapping("/analyzeScores")
   public ResponseEntity<StudentDTO> analyzeScores(@RequestBody @Valid StudentDTO rq) {
       return new ResponseEntity<StudentDTO>(service.analyzeScores(rq), HttpStatus.OK);
   }
}

Exception controller:

import com.practicastesting.diploma.dto.ErrorDTO;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import java.util.Objects;

@ControllerAdvice
public class ExceptionController {
   @ExceptionHandler(MethodArgumentNotValidException.class)
   @ResponseBody
   @ResponseStatus(value = HttpStatus.BAD_REQUEST)
   protected ResponseEntity<ErrorDTO> handleValidationExceptions(MethodArgumentNotValidException e) {
       ErrorDTO error = new ErrorDTO("MethodArgumentNotValidException", Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage());
       return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
   }

}

Well, with that, when I try to send some json like:

{
   "studentName": "a",
   "subjects": 
       [
           {
               "name": "Math",
               "score": 115
           },
           {
               "name": "Whatever",
               "score": 7
           },
           {
               "name": "Chemistry",
               "score": 6
           }
       ]
}

It should give me an error, telling me the message of each of the validations that are defined into the DTO, but is not giving me any error or exception, it just save it into the repository, and working normally.

More details:

I’m using:

  • Spring boot 2.5.4
  • Java 11

my pom.xml looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <parent>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-parent</artifactId>
       <version>2.5.4</version>
       <relativePath/> <!-- lookup parent from repository -->
   </parent>
   <groupId>com.practicastesting</groupId>
   <artifactId>diploma</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <name>diploma</name>
   <description>Demo project for Spring Boot</description>
   <properties>
       <java.version>11</java.version>
   </properties>
   <dependencies>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-web</artifactId>
       </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-validation</artifactId>
           <version>2.4.2</version>
       </dependency>

       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-devtools</artifactId>
           <scope>runtime</scope>
           <optional>true</optional>
       </dependency>
       <dependency>
           <groupId>org.projectlombok</groupId>
           <artifactId>lombok</artifactId>
           <optional>true</optional>
       </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-test</artifactId>
           <scope>test</scope>
       </dependency>
       <dependency>
           <groupId>javax.validation</groupId>
           <artifactId>validation-api</artifactId>
           <version>2.0.1.Final</version>
       </dependency>
       <dependency>
           <groupId>org.hibernate.validator</groupId>
           <artifactId>hibernate-validator</artifactId>
           <version>6.0.13.Final</version>
       </dependency>
       <dependency>
           <groupId>org.glassfish</groupId>
           <artifactId>javax.el</artifactId>
           <version>3.0.0</version>
       </dependency>
   </dependencies>

   <build>
       <plugins>
           <plugin>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-maven-plugin</artifactId>
               <configuration>
                   <excludes>
                       <exclude>
                           <groupId>org.projectlombok</groupId>
                           <artifactId>lombok</artifactId>
                       </exclude>
                   </excludes>
               </configuration>
           </plugin>
       </plugins>
   </build>

</project>

If u need more details just ask, ill give them all

Advertisement

Answer

Hello @Sebastián Villegas, I downloaded your project from GitHub and proved it with the request that you added above and the program is doing the corresponding validation (result that I obtained bellow):

{
    "name": "MethodArgumentNotValidException",
    "description": "Minimum 2 letters, max 50"
}

Rebuild your project. If you are using IntelliJ IDEA as your IDE, in the menu go to Build -> Rebuild Project

Advertisement