2
\$\begingroup\$

So we have a RESTful webservice that implements CRUD operations for a model, like this one:

class MyModel {
    private long id;
    private String name;
    // other fields
    private boolean completed;
    private boolean active;
    // getter and setters
}

In this webservice there is also a path like /service/{id}/complete that updates just the field completed to true. This indicates a final step for the creation.

The save and the complete operation are pretty simple and similar (they both end up calling a saveOrUpdate ). Where they differ is the validation. The complete validation is stricter.

The one before me declared an interface:

interface Validator<T> {
    void validate(T t);
}

And then to check that all mandatory fields where there before setting the complete attribute to true we have something like (writing in pseudocode):

MandatoryFieldsValidator implements Validator<MyModel> {

    list = {'id', 'active'}

    public void validate(MyModel model) {
        foreach(element in list) {
            if(myModel.get(element) is null) throw ValidationException(element + " is mandatory");
        }
    }
}

So then I needed another type of validator and started doing something like this because I needed specific controls over the name field:

NameValidator implements Validator<MyModel> {
    public void validate(MyModel model) {
        if(model.name is null or empty) 
        throw ValidationException(element + " is mandatory");
        if(model.name.startswith("something"))
            throw ValidationException("something not valid prefix");
        if(model.name.length > 10)
        throw ValidationException("too long");      
    }
}

The controller had an attribute of type Validator that instantiated a MandatoryFieldsValidator so I added another attribute of the same type instantiating a NameValidator.

Now what I don't like about this:

  • The fact that I need to add a new attribute to the class as soon as I have a new validator to use;
  • The fact that I'm repeating checks in different validators because even if name is not included in the MandatoryFieldValidator I'm applying the same logic inside NameValidator (is null or empty);
  • I will also add a new type of model and a MandatoryFieldValidator<NewModel> with the same type of control logic is a non-sense.

Can you give me some advice? I'm looking into a general pattern to organize this kind of validation but I'm using Java so if you have some Java specific solution is ok.

\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

You could use the composite pattern to create a tree of Validator instances. Each node would validate its with its own Validator before delegating to children (if any). This way children don't need to check again what was already validated in parent nodes

public class ValidatorTree<T> implements Validator<T> {

    private Validator<? super T> node;
    private List<Validator<? super T>> children;

    // constructor etc. snipped for brevity

    @Override
    public void validate(T t) {
        node.validate(t);
        for (Validator<? super T> child : children) {
            child.validate(t);
        }
    }
}

This way you can bundle several validators into one (so only one root validator needs to be referenced). And validation order is guaranteed, so no need to perform duplicate checks.

Edit (in response to comment)

A Validator for Model1 may very well be different from a Validator for Model2. If Validators are to be reused for different models you can define interfaces that define the common parts to be validated.

e.g.

public interface Named {

    String getName();
}

and a matching NameNotNullValidator :

public class NameNotNullValidator implements Validator<Named> {
    @Override
    public void validate(Named named) {
        if (named.getName() == null) {
            throw new ValidationException(/* appropriate message here */);
        }
    }
}

And this Validator can be reused in validator trees for all models that implement Named. Note that I adapted the generics in ValidatorTree for this.

\$\endgroup\$
4
  • \$\begingroup\$ Ok but that doesn't resolve my problem when it comes to <T>. With this solution I still need, for example, two mandatoryFieldValidators one for each <T> I introduce. I'm probably missing something in the reasoning. \$\endgroup\$
    – dierre
    Commented Aug 13, 2013 at 16:26
  • \$\begingroup\$ Edited response \$\endgroup\$
    – bowmore
    Commented Aug 13, 2013 at 18:43
  • \$\begingroup\$ Ok. Question: if in a model I have two field that needs a "notNullValidator" what should I do? Right now I see two solution: add a method getOtherField in the Named interface or add a new interface OtherField with method getOtherField and then I have to add a second Validator<OtherField> with the same logic of NameNotNullValidator. Is my reasoning wrong? Because in the first case I'll have an Interface with the same field of the model, in the second case I'll have logic replicated. \$\endgroup\$
    – dierre
    Commented Aug 14, 2013 at 7:21
  • \$\begingroup\$ I thought the Validators worked on the model, not on the fields. i.e. T is a model class. Of course these can use reusable field validating components, I'm just not sure whether they have to implement the Validator interface. \$\endgroup\$
    – bowmore
    Commented Aug 14, 2013 at 9:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.