@GroupSequence
should work according to Defining group sequences
By default, constraints are evaluated in no particular order, regardless of which groups they belong to. In some situations, however, it is useful to control the order in which constraints are evaluated.
One thing to note is the ordering should be (IMO):
NotNull -> NotEmpty -> NotBlank -> UUID
As NotEmpty
already checked NotNull
and NotBlank
already checked NotEmpty
.
Below test is using spring boot 3.0.1 running with openjdk 20
import jakarta.validation.GroupSequence;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import org.hibernate.validator.constraints.UUID;
// validation is applied following this order
@GroupSequence({Null.class, Empty.class, Blank.class, UID.class, UserRequest.class})
public class UserRequest {
// not related to annotation order here
@NotBlank(groups = Blank.class, message = "userId id can not be blank.")
@NotEmpty(groups = Empty.class, message = "userId id can not be empty.")
@NotNull(groups = Null.class, message = "userId id can not be null.")
@UUID(groups = UID.class)
private String userId;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
}
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.params.provider.Arguments.arguments;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validator;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.Set;
import java.util.stream.Stream;
@SpringBootTest
public class UserRequestValidateTest {
@Autowired
private Validator validator;
@ParameterizedTest
@MethodSource("invalidUserIds")
void testUserValidationOrder(String userId, String expectedMessage) {
UserRequest userRequest = new UserRequest();
userRequest.setUserId(userId);
Set<ConstraintViolation<UserRequest>> violations = validator.validate(userRequest, Null.class);
assertTrue(violations.size() == 1);
assertEquals(expectedMessage, violations.iterator().next().getMessage());
}
@MethodSource
public static Stream<Arguments> invalidUserIds() {
return Stream.of(arguments(null, "userId id can not be null."),
arguments("", "userId id can not be empty."),
arguments(" ", "userId id can not be blank."),
arguments("not uuid", "must be a valid UUID"));
}
}