0

Problem

I have the following constraints on userUuid and itemUuid:

  • Both strings must not be null.
  • Both strings must be UUIDs (eg. f1aecbba-d454-40fd-83d6-a547ff6ff09e).
  • The composition (userUuid, itemUuid) must be unique.

I tried to implement the validation in my controller like:

@RestController
@Validated // (1)
public class CartItemController {

    @PostMapping("/me/carts/{itemUuid}")
    @ResponseStatus(HttpStatus.CREATED)
    public void addItem(@PathVariable("itemUuid") String itemUuid,
                        Authentication auth) {
        CartItemId id = getCartItemId(getUserUuidFrom(auth), itemUuid);
        ...
    }

    @Unique // (4)
    public CartItemId getCartItemId(@NotNull @Uuid String userUuid, // (2)
                                    @NotNull @Uuid String itemUuid) { // (3)
        return new CartItemId(userUuid, itemUuid);
    }
    ...
}

@Uuid and @Unique are custom constraints. Method validation is enabled in (1). (2) are the contraints for the user UUID. (3) are the constraints for the item UUID. The unique constraint is applied to the returned CartItemId in (4). However, the parameters and the return value are never validated. Neither for the standard @NotNull constraint nor for my custom constraints. I receive HTTP status 201 Created instead of 400 Bad Request.

What am I doing wrong?

Stuff that works

The following code works for the item UUID:

@RestController
@Validated
public class CartItemController {

    @PostMapping("/me/{itemUuid}")
    @ResponseStatus(HttpStatus.CREATED)
    public void addItem(@PathVariable("itemUuid") @Uuid String itemUuid, // (1)
                        Authentication auth) {
        ...
    }

}

Adding the @Uuid to the path variable parameter works. Values like anInvalidUuid are rejected. I also tested the @Unique constraint in other use cases and it worked perfectly.

What is the difference between addItem() and toId()?

Versions

I am using Java 1.8 and Spring Boot 2.0.0.RELEASE. org.hibernate.validator:hibernate-validator:6.0.7.Final is on my classpath.

Marian
  • 351
  • 2
  • 12

1 Answers1

2

Validation of method arguments is based on AOP: a validating proxy intercepts the method call and validates the argument before delegating (if everything is valid), to the actual method.

You're calling the getCartItemId() method from another method of the same class. So the method call doesn't go through the proxy. Only inter-bean calls can be intercepted.

So, in short, getCartItemId should be in a separate bean, injected into your controller.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • Thank you, I moved `toId()` to a different class annotated with `@Component` (making it a bean) and `@Validated`. It works perfectly. I will try to find a cleaner solution, but your answer helped a lot. – Marian Mar 10 '18 at 16:34