title: How to validate an attribute based on another in spring-boot in a clean way?
body: <p>I am validating REST service request/bean in a spring-boot 2.3.1.RELEASE web application. Currently, I am using Hibernate Validator, though I am open to using any other way for validation.</p>
  <p>Say, I have a model <code>Foo</code>, which I receive as a request in a <code>Rest Controller</code>. And I want to validate if <code>completionDate</code> is not <code>null</code> then <code>status</code> should be either &quot;complete&quot; or &quot;closed&quot;.</p>
  <pre class="lang-java prettyprint-override"><code>@StatusValidate
  public class Foo {
      private String status;
      private LocalDate completionDate;
      // getters and setters
  }
  </code></pre>
  <p>I created a custom class level annotation <code>@StatusValidate</code>.</p>
  <pre class="lang-java prettyprint-override"><code>@Constraint(validatedBy = StatusValidator.class)
  @Target(ElementType.TYPE)
  @Retention(RetentionPolicy.RUNTIME)
  public @interface StatusValidate {
  
      String message() default &quot;default status error&quot;;
  
      Class&lt;?&gt;[] groups() default {};
  
      Class&lt;? extends Payload&gt;[] payload() default {};
  }
  </code></pre>
  <p>I created <code>StatusValidator</code> class.</p>
  <pre class="lang-java prettyprint-override"><code>public class StatusValidator implements ConstraintValidator&lt;StatusValidate, Foo&gt; {
  
      @Override
      public void initialize(StatusValidateconstraintAnnotation) {
      }
  
      @Override
      public boolean isValid(Foovalue, ConstraintValidatorContext context) {
          if (null != value.getCompletionDate() &amp;&amp; (!value.getStatus().equalsIgnoreCase(&quot;complete&quot;) &amp;&amp; !value.getStatus().equalsIgnoreCase(&quot;closed&quot;))) {
              context.disableDefaultConstraintViolation();
              context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate()).
                      .addPropertyNode(&quot;status&quot;).addConstraintViolation();
              return false;
          }
          return true;
      }
  }
  </code></pre>
  <p>When I validate <code>Foo</code> object (by using <code>@Valid</code> or <code>@Validated</code> or manually calling the <code>validator.validate()</code> method), I get following data in the <code>ConstraintViolation</code>.
  Code:</p>
  <pre class="lang-java prettyprint-override"><code>// Update.class is a group
  Set&lt;ConstraintViolation&lt;Foo&gt;&gt; constraintViolations = validator.validate(foo, Update.class);
  constraintViolations.forEach(constraintViolation -&gt; {
      ErrorMessage errorMessage = new ErrorMessage();
      errorMessage.setKey(constraintViolation.getPropertyPath().toString());
      errorMessage.setValue(constraintViolation.getInvalidValue());
      // Do something with errorMessage here
  });
  </code></pre>
  <p><code>constraintViolation.getPropertyPath().toString()</code> =&gt; status</p>
  <p><code>constraintViolation.getInvalidValue()</code> =&gt; (Foo object)</p>
  <p>How can I set an invalid value (actual value of <code>status</code> attribute) in custom <code>ConstraintValidator</code> or anywhere else so that <code>constraintViolation.getInvalidValue()</code> returns value of <code>status</code> attribute?
  <strong>OR</strong>
  Is there a better way of validating request payload/bean where validation of an attribute depends on another attribute's value?</p>
  <p><strong>Edit :</strong>
  I can do something like</p>
  <pre class="lang-java prettyprint-override"><code>if(constraintViolation.getPropertyPath().toString().equals(&quot;status&quot;)) {
      errorMessage.setValue(foo.getStatus());
  }
  </code></pre>
  <p>but this would involve maintaining the String constant of attribute names somewhere for eg. <code>&quot;status&quot;</code>. Though, in the <code>StatusValidator</code> also, I am setting the attribute name <code>.addPropertyNode(&quot;status&quot;)</code> which also I would like to avoid.</p>
  <hr />
  <p><strong>Summary :</strong>
  I am looking for a solution (not necessarily using custom validations or hibernate validator) where</p>
  <ol>
  <li>I can validate json requestor or a bean, for an attribute whose validations depends on values of other attributes.</li>
  <li>I don't have to maintain bean attribute names as String constants anywhere (maintenance nightmare).</li>
  <li>I am able to get the invalid property name and value both.</li>
  </ol>