0

I wrote example of endpoints to understand the meaning of my question.

I realised that my tests didnt pass due to the @Valid annotation.

Eg. I got two endpoints if someone is hitting the old one there is a need to check if Email is set becuase it has a @NotBlank annotation. But when I'm asking my endpoint with a set email the @Valid is not executed I realised that after doing tests with invalid data. And I cannot set the @Valid in the oldPutContact because there are some contacts without email.

My question is why putContact didn't execute the @Valid annotation.

    @PutMapping(value = "/contact/{contactid}", )
    public String oldPutContact(@RequestBody Contact contact)
        if(StringUtils.isBlank(contact.getEmail())){
            contact.setEmail("randomEmail@ups.cm") ;
        }
        return putContact(contact);
    }
    @PutMapping(value = "/contact/update/{contactid}")
    public String putContact(@RequestBody @Valid Contact contact) {
        contactService.updateContact(contact);
    }

Imagine Contact Entity looks like this

 @Builder(toBuilder=true)
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class Contact {

        private static final String SOME_PATTERN = "";
       private static final String SOME_EMAIL_PATTERN = "";
        private static final String SOME_PATTERN2 = "";
      
        @NotBlank
        private String id;

        @NotNull
        private Boolean isActive;

        @NotBlank
        @Pattern(regexp = SOME_PATTERN)
        private String name;

        @NotBlank
        @Pattern(regexp = SOME_PATTERN)
        private String surname;
        
       @NotBlank
        @Email(regexp = SOME_EMAIL_PATTERN)
        private String email;

        @NotBlank
        @Pattern(regexp = SOME_PATTERN2)
        private String telephone;

    }
  • 2
    And how you supposed to make Spring know how *exactly* passed String should be validated? – Vasily Liaskovsky Oct 06 '21 at 12:24
  • The code is an example to understand the sense of it. I have an Entity where i use a lot of annoation like Pattern, NotNull, NotBlank etc. If I use the Valid annotation I say spring that he needs to check the fields in the Entity. He is doing that but not in the case above when Im first hitting oldPutConctact endpoint with an setEmail and then putContact. If I'm hitting only putContact endpoint the Valid annotation is considered. – tooFastForSatan Oct 06 '21 at 12:32
  • Test are already done but this is the one case when the test didnt pass and I dont understand why the VAlid annotation is not executed – tooFastForSatan Oct 06 '21 at 12:34
  • Show the full model class you pass to `putContact` endpoint, or at least it's essential part (email) – Nikolai Shevchenko Oct 06 '21 at 12:38
  • How should spring validate the entity if all it has is a `String`? Your method signature takes a `String` **not** your entity (this `putContact(@RequestBody @Valid String contact)` is what you posted!). If that is just a typo remove the `javax.validation` dependency you have and add `spring-boot-starter-validation`. Finally the internal call won't execute the `@Valid` as that is part of the request processing which you bypass here, when used with `@Validated` it won't work either as that uses AOP and thus proxies for which it doesn't pass through the proxy with an internal method call. – M. Deinum Oct 06 '21 at 17:00

1 Answers1

0

Firstly you should define the validation rule for your parameters. For example(Note the NotBlank annotation):

@Entity
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @NotBlank(message = "Name is mandatory")
    private String name;

    @NotBlank(message = "Email is mandatory")
    private String email;

    // standard constructors / setters / getters / toString
    
}

Then you can use the valid annotation in rest api controller. Like this:

@RestController
public class UserController {

    @PostMapping("/users")
    ResponseEntity<String> addUser(@Valid @RequestBody User user) {
        // persisting the user
        return ResponseEntity.ok("User is valid");
    }

    // standard constructors / other methods

}

You may not define the validation rule. So spring doesn’t know how to validate the parameter.

Please refer to Spring validation for further information.

----By reading the comment from @nusia, add the following description.

From the sample code "public String putContact(@RequestBody @Valid String contact)", I can't see where you define the @NotBlank annotation to parameter String contact, or did you mean the type of argument "contact" is not string? If the type of "contact" is a defined entity and its email field has the NotBlank annotation. Then calling your new endpoint "putContact" from HTTP PUT request will fire the spring validation, but if you mean you call the new method "putContact" from your old method "oldPutContact" the spring validation will not be fired, the reason is similar to Call spring annotation method from same class.

bluezealot
  • 99
  • 1
  • 4
  • Maybe I defined the question wrong. I got everything what u said and above the RestContoller annotation there must be also a Validated annotation. But my problem is this one consider that an old endpoint exists for putMapping so two endpoints one old one new Endpoint. They need to be there. And sometimes Based on user example the is email for old users is sometimes is not set so i need to set it manually before doing something in my service. Will be continued – tooFastForSatan Oct 06 '21 at 12:46
  • So considere two cases some users with set email and some user without set email. When a user with set email call the old endpoint where we check if the email is not blank and where is not a Valid annotation due some user without set email.and we redirect hime to the new endpount in user case addUser /users the Valid annotation is not executed. – tooFastForSatan Oct 06 '21 at 12:49
  • And thats the question why Spring didnt see the @Valid annotation – tooFastForSatan Oct 06 '21 at 12:49
  • I realised that after doing some test with invalid data i saw that this annotation is not executed – tooFastForSatan Oct 06 '21 at 12:50
  • No you don't need the `@Validated` on the controller (please stop doing that as that serves a totally different use case). – M. Deinum Oct 06 '21 at 17:01
  • @nusia I edited the answer by adding some description, please have a look. – bluezealot Oct 07 '21 at 04:22
  • @bluezealot Thank your for you comment. I think the last sentence answeared my question. Will defentetly rn dig deep into the article. Thanks – tooFastForSatan Oct 07 '21 at 09:27