Validating fields with rules that depend on other fields

I want to validate fields that have rules that depend on value of another field. Simple example would be:

public class Bean { Date start; // has to be before end Date end; // has to be after start } The solution I have now uses value change listeners to add and remove validators or just custom vaadin validators, but the problem is that now the business logic is all described in a long mess of value-change listeners and very heavily coupled to Vaadin classes. While I don’t see the need to change the UI framework, I do need to validate objects outside of UI code too and creating vaadin forms just to check if an object is valid seems like a bad idea.

One solution that I thought of is to use custom annotations, but I have not found a way to creat field annotations that can access other fields. I could use class level annotation, but in this case Vaadin has no idea which field is the offending one, only that the object is not valid.

public class Bean {
// this would work with Vaadin, but AFAIK you cannot pass the end field to the validator this way
    @IsBefore("end") 
    Date start; // has to be before end
    Date end; // has to be after start
}
[/code][code]
// this time annotation works, but its not possible to determine the invalid field
@IsBefore("start", "end") 
public class Bean {
    Date start; // has to be before end
    Date end; // has to be after start
}

Of course there could be other solutions aside from validation annotations, but I would like something that could work both without vaadin and which would also be easily used with vaadin.

Has anybody done something like this before?

Hi Kristian. Haven’t done this, but you should able to access the other fields using reflection. I actually found an example of creating a
Bean Validation for a date range
which does just that. It should work together with the
BeanValidator
. And ofcourse also without Vaadin.

This kind of cross-field validation is rather tricky with core Vaadin. You should check out my recent blog entry about
cross-field validation in Viritin forms
. It nowadays supports both programmatic cross field validators and JSR 303 style annotation (like you have in your example).

cheers,
matti

This is indeed tricky, because of the field buffering.

When using Grid, there is a not-too-complex way to do cross field validation (in the row editor). A normal validator gets the “uncommited” value for testing it. Other fields are still uncommited (their values have not gotten to your domain objects yet), but the uncommited values of other fields can be accessed through the grid’s column’s editor fields.

For example, to validate input on field A (column A of the grid), rejecting any value that is larger than field B (column B of the grid):

BeanItemContainer<Activity> beanItemContainer = new BeanItemContainer(...);
Grid grid = new Grid("name", beanItemContainer);
grid.getColumn("ColumnA").getEditorField().addValidator(new Validator()
        {
            @Override
            public void validate(Object valueOfColumnA) throws InvalidValueException
            {
                    Object valueOfColumnB = grid.getColumn("ColumnB").getEditorField().getValue();
                    if (! valueOfColumnA > valueOfColumnB ) {throw new InvalidValueException("A cannot be larger than B");}
            }
        });

The problem here again is that the validation(business) rules are written in vaadin code, which is what i was trying to avoid. I would like to have the business rules described in some more general way, so I could also use them outside a vaadin application. E.g. I have a bunch of POJOs that in vaadin application are bound to forms and validated there, but if I want to validate them elsewhere I have no way of doing this other than creating vaadin objects and validating those objects even though I don’t need to show them in any kind of UI.

What I ended up doing was writing the rules in a configuration file and then when the form is generated, vaadin validators are generated according to the rules written in the conf, but of course I had to write the engine that creates those validators myself.

In general I have found that having business rules written in Vaadin code is not a good idea. It works for simpler applications, but if the rules are more complex, you end up with a mess of vaadin listeners. This makes the code harder to understand, debug and test.

Hi Kristian,

I think you are on right track here. For exact that reason I tend to use JSR 303 validation in my projects and examples. Was there some specific reason why you didn’t use JSR 303 as your implementation? With it you can for example use the same validation rules both in backend and UI code.

__
m

I don’t think there was any specific reason other than time it would have taken me to figure it all out. There was already a way to read some other, non-validation related rules from a configuration file and applying them in this project and in this occasion it made sense to keep everything there.

I think that for that cross-field validation issue that i posted initially I would have still needed to implement some sort of mechanism to create vaadin validators for individual fields.
I also had a requirement to change validation rules on same object depending on the situation, which would have been more difficult to do using the annotations. Likely using xml configuration files instead of annotations would have been better for that.

So starting from scratch, I probably would have used JSR 303 validation. But this was an older project and I went for a solution that I was able to do given time constraints.

In vaadin 8 you have BeanValidationBinder which add JSR-303 validation rules to a Binder.
Perhaps you can create a new BusinessValidationBinder and add your validation rules “automatically”. (I don’t know how you validate your data).

Does this work with Vaadin 8 ? I tried and some core features (bean level validation) were not here :confused:

Jean-Christophe, upvote this issue: https://github.com/vaadin/framework/issues/8498

For Viritin I built a pretty advanced bean level validation support, but I haven’t found time to build a V8 Binder compatible version of that.

cheers,
matti

Done (I should do it before :stuck_out_tongue: ).
I used Viritin in my Vaadin 7 project because it’s a great add-on ;). (i thought the main features of the addon will be added in the core of Vaadin but there is still some work :slight_smile: )