title: Spring Custom Annotation Validation with multiple field
body: <p>A little greedy question here, hope this one could also help others who want to know more about annotation validation</p>
  
  <p>I am currently studying Spring, and for now, I am planning to try out the customize annotated validation.</p>
  
  <p>I have searched a lot and now I know there are mainly two kinds of validations, one is used for the controller, and the other is the annotation method using @Valid</p>
  
  <p>So here's my scenario:
  Suppose I have two or more fields which can be null when they are ALL NULL.
  But only when one of those fields contains any value except an empty string, those fields are required to have input. And I had two ideas but didn't know how to implement them correctly.</p>
  
  <p>Here's the Class Example: </p>
  
  <pre><code>public class Subscriber {
      private String name;
      private String email;
      private Integer age;
      private String phone;
      private Gender gender;
      private Date birthday;
      private Date confirmBirthday;
      private String birthdayMessage;
      private Boolean receiveNewsletter;
  
      //Getter and Setter
  }
  </code></pre>
  
  <p>Suppose I want that the birthday and confirmBirthday field need to be both null or the oppose, I may want to annotate them using one annotation for each of them and looks like this:</p>
  
  <pre><code>public class Subscriber {
      private String name;
      private String email;
      private Integer age;
      private String phone;
      private Gender gender;
  
      @NotNullIf(fieldName="confirmBirthday")
      private Date birthday;
  
      @NotNullIf(fieldName="birthday")
      private Date confirmBirthday;
  
      private String birthdayMessage;
      private Boolean receiveNewsletter;
  
      //Getter and Setter
  }
  </code></pre>
  
  <p>So i do need to create the validation Annotation like this:</p>
  
  <pre><code>@Documented
  @Constraint(validatedBy = NotNullIfConstraintValidator.class)
  @Retention(RetentionPolicy.RUNTIME)
  @Target({ ElementType.METHOD, ElementType.FIELD })
  public @interface NotNullIf {
  
      String fieldName();
  
      String message() default "{NotNullIf.message}";
      Class&lt;?&gt;[] group() default {};
      Class&lt;? extends Payload&gt;[] payload() default {};
  }
  </code></pre>
  
  <p>And After that i will need to create the Validator itself:</p>
  
  <pre><code>public class NotNullIfConstraintValidator implements ConstraintValidator&lt;NotNullIf, String&gt;{
  
      private String fieldName;
  
      public void initialize(NotNullIf constraintAnnotation) {
          fieldName = constraintAnnotation.fieldName();
      }
  
      public boolean isValid(String value, ConstraintValidatorContext context) {
          if(value == null) {
              return true;
          };
          //TODO Validation
          return false;
      }
  
  }
  </code></pre>
  
  <h1>So how can it be achievable?</h1>
  
  <p>For another idea using the same Class as an example which said that i want birthday, confirmBirthday and birthdayMessdage can only be null or the oppose at the same time.
  I may require to use the class annotated validation this time for cross-field validation.</p>
  
  <p>Here's how i suppose to annotate the class:</p>
  
  <pre><code>@NotNullIf(fieldName={"birthday", "confirmBirthday", "birthdayMessage"})
  public class Subscriber {
      //Those field same as the above one
  }
  </code></pre>
  
  <p>So when one of that field is not null, the rest of them also needs to be entered on the client size.
  Is it Possible?</p>
  
  <p>I have read this article: <a href="https://stackoverflow.com/questions/37750656/how-to-access-a-field-which-is-described-in-annotation-property">How to access a field which is described in annotation property</a></p>
  
  <p>But I still confusing on how the annotation validation works from those elements I listed above.
  Maybe I need some detail explanation on that code or even worse I may need some basic concept inspection.</p>
  
  <p>Please Help!</p>