Annotation Type Value.Check


  • @Documented
    @Target(METHOD)
    public static @interface Value.Check

    Annotates method that should be invoked internally to validate invariants after instance had been created, but before returned to a client. Annotated method must be parameter-less (non-private) method and have a void return type, which also should not throw a checked exceptions.

     @Value.Immutable
     public abstract class NumberContainer {
       public abstract List nonEmptyNumbers();
    
       @Value.Check
       protected void check() {
         Preconditions.checkState(!nonEmptyNumbers().isEmpty(),
             "'nonEmptyNumbers' should have at least one number");
       }
     }
    
     // will throw IllegalStateException("'nonEmptyNumbers' should have at least one number")
     ImmutableNumberContainer.builder().build();
     

    Precondition checking should not be used to validate against context dependent business rules, but to preserve consistency and guarantee that instances will be usable. Precondition check methods runs when immutable object instantiated and all attributes are initialized, but before returned to caller. Any instance that failed precondition check is unreachable to caller due to runtime exception.

    There's additional variant of using this annotation to compute normalized value. This should be a last-resort solution as implementation might be brittle and error-prone. If you declare return type of validation method with return type specified as abstract value type, this validation method will also be able to return substitute instance. Normalized instance should always be of the immutable implementations type, otherwise ClassCastException will occur during construction. Be warned that it's easy introduce unresolvable recursion if normalization is implemented without proper or with conflicting checks. Always return this if value do not require normalization.

     @Value.Immutable
     public interface Normalize {
       int value();
    
       @Value.Check
       default Normalize normalize() {
         if (value() == Integer.MIN_VALUE) {
           return ImmutableNormalize.builder()
               .value(0)
               .build();
         }
         if (value() < 0) {
           return ImmutableNormalize.builder()
               .value(-value())
               .build();
         }
         return this;
       }
     }
    
     int shouldBePositive2 = ImmutableNormalize.builder()
         .value(-2)
         .build()
         .value();