Blog on Vaadin

Hi Everybody,

I’ve just developed a sample Vaadin application using Converters, Validator and ObjectProperty. Take a look at:

http://razvanml.github.io/reco-link/2016-12-05/Vaadin-Temperature-Conversion/

The only issue I encountered was checking a control for error: getComponentError didn’t return anything but null (maybe i’ve called it in a wrong context?). I’ve achieved the test by calling validate() on the text field.

Thanks,
Razvan

Hi Razvan,

The explanation
“Note the validate call. This is necessary because as of Vaadin 7.7.5, the method getComponentError() returns null even for invalidated controls.”
is not quite correct. I mean, it does not explain what your plan was with getComponentError() – hence what do you accomplish with validate() now?
And also, validated controls most likely are not in an error state (so ‘null’ is a valid return value). The word ‘even’ is misleading here.

Let’s say you are surprised that components that do not pass validation do not set the component error using
‘setComponentError()’. This
is
surprising at first, but you are somewhat abusing the API. Maybe we need to
look into documenting it more thoroughly.

It is however quite unusual to validate() all the text fields as a result of an input to one text field.

The code downloadable from your site also is slightly different than the code shown on it.

In particular,

temp.addValueChangeListener(e->{
for (TextField tf : fields) { // just assign “fields” before adding lambda listener instances to “temp”, so you don’t need to check " if (fields != null) " as in the website’s code.
try {
tf.validate();
} catch(RuntimeException ex) { // should really be InvalidValueException
System.out.println(tf.getComponentError().getFormattedHtmlMessage()); // DANGER HERE: NPE LURKING
tf.discard();
}
}
});
The line with the ‘System.out’ will throw NPE when a text field is validated, that is in an error state from a previous input into itself.

It always happens, for example, when you enter “-400.00” in the Kelvin text field and then “100” in the Celsius field.

This is not that surprising: While you have inputted text to A DIFFERENT text field, as a result of validate()ing
all the text fields the one with an invalid value throws the InvalidValueException that you catch as a RuntimeException.
However, this text field’s error text is NULL, because there was no implicit validation - the framework has not had
a chance to catch the InvalidValueException and set the error message.

I must admit I have not fully debugged it yet, but hey - the point is the way you’re using the API you cannot be sure the error message is set, so don’t use that error message as if it was known to be non-null.

What you really want to do, also to clear the error state and to make sure any old bad entries are removed, is to discard any such entries:

    temp.addValueChangeListener(e->{
        for (TextField tf : fields) {
            tf.discard();
        }            
    });

HTH,
–Enver

Hi Enver,

Thanks for the observations, I will apply your changes. The System.out.println was added for debugging, and forgot about. Of course it throws a NullPointerException, this was the issue I was investigating with the code.

Am I right that there is no way to test whether a TextField failed validation? Calling discard for each field is also a good solution, probably better than unnecessary re-running of validator.

Thanks,
Razvan

Hi Razvan,

Am I right that there is no way to test whether a TextField failed validation?
I would have thought that a TextField that failed validation would have its
tf.isValid() == false. Does it not work?
Of course, if you want to know the state, then do not re-run validate() before
calling isValid() with a validator that would validate okay, like you did.

HTH,
–Enver

Hi Enver,

I’ve updated the blog (addressed the issues you mentioned), also, isValid works. I’ve looked in the sourcecode of isValid, it calls the validators and returns false on exception.

Thanks,
Razvan

Hi Razvan,

sounds nice! Have a good day!

Best Regards,
–Enver