简体   繁体   中英

Optional with @NotBlank giving error while @Size not giving for a Immutable Class using Javax validation

I have following POJO:

import java.util.Optional;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;

import org.immutables.value.Value;

@Value.Immutable
public interface ABC {
    Optional<@NotBlank String> test();

    Optional<@Size(max = 280) String> testSize();
}

I am using javax validation to validate objects of class ABC like following:

public static Set<TestConstraintViolation> validateInternalTest(final Object type, final Class<?>... groups) {
        Set<TestConstraintViolation> violations = new HashSet<>();
        for (Method method : type.getClass().getInterfaces()[0].getDeclaredMethods()) {
            try {
                VALIDATOR.validateReturnValue(
                        type,
                        method,
                        method.invoke(type),
                        groups).forEach(constraint -> {
                    TestConstraintViolation testConstraintViolation = new TestConstraintViolation(
                            method.getName(),
                            constraint.getMessageTemplate()
                    );
                    violations.add(testConstraintViolation);
                });
            } catch (IllegalAccessException | InvocationTargetException e) {
                throw new IllegalStateException("", e);
            }
        }
        return violations;
    }

Now, when I try to validate with this validator function objects of ABC, I am seeing a weird issue:

@Test
public void test() {
    ABC abc = ABCType.builder().build();
    assertThat(validateInternalTest(abc))
            .hasViolation("test", "{javax.validation.constraints.NotBlank.message}");

    ABC abc2 = ABCType.builder().test("test").build();
    assertThat(validateInternalTest(abc2))
            .hasNoViolations();
}

With abc object, it returns violations if test is not passed even if it is optional while not passing testSize works fine.

According to me, with Optional, both of them should work. Isn't it?

Is it some issue with Immutables or javax validation? Please help.

What is the Optional type? Optional is a new container type that wraps a single value, if the value is available. So it's meant to convey the meaning that the value might be absent. Take for example this method:

If you are using Optional which means value might be absent and using @NotBlank in conjunction with Optional doesn't seem to be a wise idea to me.

  • The JSR 380 spec (Bean Validation 2.0) treats empty optionals ( Optional.empty() ) as null .

  • Most constraints (including @Size) do not consider null to be a constraint violation which is why the empty optional (treated as null ) passes validation. It is also the reason that one often comes across @NotNull @Size(min = 1, max = 2) String x; (ie check for both size and notnull).

  • The @NotBlank constraint however is one of the exceptions that does not allow null s ( considers them to be violations ). That is why @NotBlank fails where most others would not.

A similar question was raised as a Hibernate Validator issue here . Please see the first response in the issue (by Guillaume Smet):

This is a choice we made when writing the Bean Validation 2.0 specification. We consider the value of an empty Optional as null.

Most of the constraints are not concerned as they don't fail for null but indeed for @NotBlank , we consider null as an invalid value.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM