'What is the best way to Validate one field in Java based on another field using hibernate-validator?

I have a class that consists of many fields and these fields have the hibernate-validator Annotations so if the invalid data enters then it can throw the respective message.

Some of the fields are interdependent meaning the field has to be Non-null if another field has a certain value. Is there a way this can be achieved using the hibernate-validator directly or do we need to write the custom validations for it?

@Data
@ToString
public class Source implements Serializable {

    @NotNull(message = "Type cannot be Null for source")
    private String type;

    //If type has any value apart from "MANUAL" then this should not be NULL @NotNull(message = "groundValue cannot be Null")
    private String groundValue;

    //If type value is "MANUAL" then this should not be NULL @NotNull(message = "manualType value cannot be Null")
    private String manualType;

    //If type value is "MANUAL" then this should not be NULL @NotNull(message = "manualURI value cannot be Null")
    private String manualURI;
}

As mentioned in the above code snipped if the conditions for groundValue, manualType and manualURI is based on the value provided to the type.

Is it possible to achieve something similar directly using the Javax valdidation? Following is the Maven dependency that I am using in my project:

<!-- For adding the validation annotations -->
<dependency>
  <groupId>io.quarkus</groupId>
  <artifactId>quarkus-hibernate-validator</artifactId>
</dependency>


Solution 1:[1]

Yes you can create your own validator.

package spike;

public interface ISource {
    String getType();

    String getGroundValue();

    String getManualType();

    String getManualURI();
}
package spike;

import java.io.Serializable;

import javax.validation.constraints.NotNull;

@SourceType
public class Source implements Serializable, ISource {

    @NotNull(message = "Type cannot be Null for source")
    private String type;

    //If type has any value apart from "MANUAL" then this should not be NULL @NotNull(message = "groundValue cannot be Null")
    private String groundValue;

    //If type value is "MANUAL" then this should not be NULL @NotNull(message = "manualType value cannot be Null")
    private String manualType;

    //If type value is "MANUAL" then this should not be NULL @NotNull(message = "manualURI value cannot be Null")
    private String manualURI;

    @Override
    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    @Override
    public String getGroundValue() {
        return groundValue;
    }

    public void setGroundValue(String groundValue) {
        this.groundValue = groundValue;
    }

    @Override
    public String getManualType() {
        return manualType;
    }

    public void setManualType(String manualType) {
        this.manualType = manualType;
    }

    @Override
    public String getManualURI() {
        return manualURI;
    }

    public void setManualURI(String manualURI) {
        this.manualURI = manualURI;
    }

    @Override
    public String toString() {
        return "Source{" +
                "type='" + type + '\'' +
                ", groundValue='" + groundValue + '\'' +
                ", manualType='" + manualType + '\'' +
                ", manualURI='" + manualURI + '\'' +
                '}';
    }
}
package spike;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = SourceTypeValidator.class)
public @interface SourceType {
    String message() default "{SourceTypeError}";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}
package spike;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class SourceTypeValidator implements ConstraintValidator<SourceType, ISource> {

    private String message;

    @Override
    public void initialize(SourceType constraintAnnotation) {
        message = constraintAnnotation.message();
    }

    @Override
    public boolean isValid(ISource value, ConstraintValidatorContext context) {
        if (value == null) {
            return true;
        }
        if ("MANUAL".equals(value.getType())) {
            return true;
        }
        boolean valid = true;
        if (value.getGroundValue() == null) {
            addConstraintViolation(context, "groundValue");
            valid = false;
        }
        if (value.getManualType() == null) {
            addConstraintViolation(context, "manualType");
            valid = false;
        }
        if (value.getManualURI() == null) {
            addConstraintViolation(context, "manualURI");
            valid = false;
        }
        return valid;
    }

    private void addConstraintViolation(ConstraintValidatorContext context, String p) {
        context.buildConstraintViolationWithTemplate(p + " cannot be Null")
                .addPropertyNode(p)
                .addConstraintViolation();
    }

}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Kristof Neirynck