Creating abstraction to validate complex objects I am trying to create a validator abstraction layer. These are the points I am trying to achieve:


My abstraction should be open for extension but closed for modification
The clients should not have a if...else block to handle success or failure scenario.


Validation statuses

public interface ValidationStatus {
    default void process() {

    }

    public static ValidationStatus fail(ValidationFailureCause cause, String messages) {
        ValidationFailure validationFailure = new ValidationFailure();
        validationFailure.setCause(cause);
        validationFailure.setErrorMessages(messages);
        return validationFailure;
    }

    public static ValidationStatus success() {
        return new ValidationSuccess();
    }
}




public class ValidationFailure implements ValidationStatus {
    private ValidationFailureCause cause;
    private String errorMessages;

    public void setCause(ValidationFailureCause cause) {
        this.cause = cause;
    }

    public void setErrorMessages(String errorMessages) {
        this.errorMessages = errorMessages;
    }

    @Override
    public void process() {
        if (ValidationFailureCause.MISSING_MANDATORY_FIELDS.equals(cause)) {
            throw new MandatoryElementsMissing(errorMessages);
        }
    }

}




public class ValidationSuccess implements ValidationStatus {

}




public enum ValidationFailureCause {
    MISSING_MANDATORY_FIELDS
}


The validators

public interface Validator&lt;T&gt; {
    /**
     * Validate an object and return the validation result as a Status.
     * 
     * @param request
     *            Data to be validated
     * @return can be ValidationFailure or ValidationSuccess class instance
     */
    ValidationStatus validate(T request);

    boolean isValid(T request);
}




public class StringValidator implements Validator&lt;String&gt; {

    @Override
    public ValidationStatus validate(String request) {
        if (isValid(request)) {
            return ValidationStatus.success();
        }

        return ValidationStatus.fail(ValidationFailureCause.MISSING_MANDATORY_FIELDS, "Missing mandatory parameter");
    }


    @Override
    public boolean isValid(String request) {
        return StringUtils.isNotBlank(request);
    }
}




public class PersonValidator implements Validator&lt;FlightProposalRequest&gt; {

    @Override
    public ValidationStatus validate(FlightProposalRequest request) {
        if (isValid(request)) {
            return ValidationStatus.success();
        } else {
            return ValidationStatus.fail(ValidationFailureCause.MISSING_MANDATORY_FIELDS, "Request is null");
        }
    }

    @Override
    public boolean isValid(FlightProposalRequest request) {
        if (request == null) {
            return false;
        }

        Validator&lt;String&gt; requestValidator = RequestValidatorFactory.getRequestValidator(String.class);

        boolean result = requestValidator.isValid(request.getArrivalAirport());
        result = result &amp;&amp; requestValidator.isValid(request.getDepartureAirport());
        result = result &amp;&amp; requestValidator.isValid(request.getDepartureDate());
        result = result &amp;&amp; requestValidator.isValid(request.getReturnDate());

        return result;
    }
}


This is my attempt at this problem. Kindly provide your feedback on my approach. With the current setup as mentioned here, my tests are passing.
So If I understand correctly, clients get an instance of Validator from the factory, call validate() and get an instance of ValidationStatus and then call process() and get an exception (or nothing). so you replaced an if...else block with a try...catch one. the client still have to check the return value to figure out what to fix. and if you ask me, it is more clear to ask
if (result == ValidationFailureCause.MISSING_MANDATORY_FIELDS)
then
} catch (MandatoryElementsMissing mem) {   


in addition, Validator interface contains a method that returns a boolean. how do you plan to prevent clients from calling it?  


If we go along with your solution: the whole ValidationStatus class tree seems redundat to me.  It is just a wrappper over throwing a user defined Exception.  It doesn't provide extra capabilities beyond translate an enum into an Exception (considering that exceptions can also have String message). So I believe a design where validate() throws an Exception provides the same functionality.  If you don't want to throw the Exception super class, you can create a ValidationException super class and have all your custom exceptions extend it (much like Java's ReflectiveOperationException)
Your design determines that for a given type, there can only be one Validator.  This may be fine for user-defined types like FlightProposalRequest but it may be too restrictive for JDK types like String.  I imagine that you want to validate that getDepartureDate() is a valid date, and perhaps validate getDepartureAirport() against predefined list of airports (perhaps an SQL query) and so on.  You should assocaite a Validator with a String name (perhaps an enum).
lastly, regartding the validation of the attributes, I believe you can write it like this:     


return requestValidator.isValid(request.getArrivalAirport())
&amp;&amp; requestValidator.isValid(request.getDepartureAirport())
&amp;&amp; requestValidator.isValid(request.getDepartureDate())
&amp;&amp; requestValidator.isValid(request.getReturnDate());     

this has the same (if not more) level of readability as the original.