4

I have defined a rest endpoint method as:

@GetMapping("/get")
public ResponseEntity getObject(@Valid MyObject myObject){....}

This maps request parameters to MyObject.

MyObject is defined as(with lombok, javax.validation annotations):

@Value
@AllArgsConstructor
public class MyObject {

    @Min(-180) @Max(180)
    private double x;

    @Min(-90) @Max(90)
    private double y;

}

But validations are not working. Even with values out of prescribed range, request doesn't throw error and goes well.

Mandroid
  • 6,200
  • 12
  • 64
  • 134
  • Did you find your answer ? We have the same problem. – Mike Mar 30 '21 at 14:53
  • Is this a regular `@RestController` or some Spring Data controller? There is some discussion below on `@RestController` vs `@RepositoryRestController` and different ways to get validation working there. – Pawel Zieminski Jan 22 '23 at 01:24

4 Answers4

5

If you on a version of Spring Boot > 2.3 it now states

Validation Starter no longer included in web starters

... you’ll need to add the starter yourself.

i.e.

For Maven builds, you can do that with the following:

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

For Gradle, you will need to add something like this:

dependencies {
  ...
  implementation 'org.springframework.boot:spring-boot-starter-validation'
}

Please refer to https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.3-Release-Notes#validation-starter-no-longer-included-in-web-starters

mkane
  • 880
  • 9
  • 16
3

Annotate your controller with org.springframework.validation.annotation.Validated

yejianfengblue
  • 2,089
  • 1
  • 14
  • 18
  • It's not true anwer. You can seen difference here https://stackoverflow.com/questions/36173332/difference-between-valid-and-validated-in-spring – Hett Apr 20 '22 at 08:44
  • This is absolutely correct. It just worked for me. Simply annotating the controller method parameter with `@Valid` did not work. I had to add `@Validated` at the controller class level. In my case this was Spring Data `@RepositoryRestController`. – Pawel Zieminski Jan 17 '23 at 17:51
  • 1
    Looks like both options are correct, @Hett, depending on the controller annotation. When it's annotated with `@RestController`, `@Validated` is not necessary at the class level to get validation to work. – Pawel Zieminski Jan 21 '23 at 00:50
  • @PawelZieminski in the questing the annotation `@Valid` already presented and this answer does not help solve the problem. – Hett Jan 21 '23 at 13:08
  • In that case the OP is probably not using a vanilla `@RestController` then. It would be good to have this detail explicit in the question. With Spring Data controllers I had to add `@Validated` otherwise validation did not work. – Pawel Zieminski Jan 22 '23 at 01:21
1

I see a couple of things here that you should fix. Let's start talking about the REST standard, the first rule is to think in endpoints as representation of resources, not operations, for example, in your code, I presume the MyObject class represents a Point (you should refactor the class to have a proper name), then the path value for the getObject can be "/point". The operations are mapped on the HTTP method, accordingly:

  • GET: Obtain info about a resource.
  • POST: Create a resource.
  • PUT: Update a resource.
  • DELETE: Delete a resource.

In getObject you're expecting to receive an object. The get method according to the REST standards means you want to retrieve some data, and usually you send some data included in the url like ../app-context/get/{id}, here the id is a parameter that tells your controller you want some info belonging to an id, so if you would invoke the endpoint like as ../app-context/get/1 to get info of some domain object identified by the number 1.

If you want to send data to the server, the most common HTTP method is a POST.

According to this, at design level you should:

  • Give a meaningful name to the MyObject class.
  • Check the operation you want to make in the getObject.
  • Assign a path to getObject representing a resource.

At code level, with the above comments, you could change this as:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class MyObject {

  @Min(-180) @Max(180)
  private double x;

  @Min(-90) @Max(90)
  private double y;
}

@PostMapping("/point")
public ResponseEntity savePoint(@RequestBody @Valid MyObject myObject) {...}

I will explain the changes:

  • Add @PostMapping to fulfill the REST standard.
  • Add @RequestBody, this annotation take the info sent to the server and use it to create a MyObject object.
  • Add @NoArgsConstructor to MyObject, by default, the deserialisation use a default constructor (with no arguments). You could write some specialised code to make the things work without the default constructor, but thats up to you.
CarlosJavier
  • 1,005
  • 1
  • 16
  • 29
1

I just had to add the following dependency to get the validations working.

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>
Milind
  • 21
  • 4