quarta-feira, 18 de outubro de 2017

JavaFX with Bean Validation and CDI 2.0

When JavaFX 2 was released I remember people looking for frameworks that would make easy to integrate JavaFX with a validation framework, a dependency injection container and other enterprise services. Currently we can integrate CDI 2.0 and Bean Validation 2.0 with a JavaFX application without the need of any external framework. In this post I will show you how to validate your javaFX screen fields using bean validation in a CDI managed application.

Before talking about all these things and JavaFX I recommend you to check the following posts from this blog:

Validating JavaFX controls using Bean Validation

With Bean Validation 2.0 we have the automatic unwrap of JavaFX properties. Which means that if you have a field that is of type of ObservableValue so the validator implementation will be able to retrieve the actual value to perform the validation. However, JavaFX control fields are still not supported, so if you try something like the code below you will have an exception when running the validator against your JavaFX controller:  

This happens because the validator implementation doesn't know how to retrieve values from a JavaFX controller. What we need to do is create a class that implements javax.validation.valueextraction.ValueExtractor. We must use the control type in this class and implement a method that will do the actual value extraction and use the annotation javax.validation.valueextraction.ExtractedValue to set the value type that will be extracted (String, Integer, LocalDate...). To avoid additional steps we use the annotation javax.validation.valueextraction.UnwrapByDefault on our implementation. This is what ValueExtractor for TextField and for DatePicker looks like:

Value Extractor for DatePicket

Value Extractor for TextField

Finally we must register it in within the bean validation framework. There are a couple of ways of doing it, we chose the SPI way, which is create a file named META-INF/services/javax.validation.valueextraction.ValueExtractor with the class name of our ValueExtractors:

Content of file META-INF/services/javax.validation.valueextraction.ValueExtractor

We could have a bean validation extension for JavaFX that should include all the extractors possible for the JavaFX controls. Let me know ff you are doing something like that and I can mention it here!

Showing validation errors to users

You will probably want to show users messages when the value they entered for the fields are not valid. Once you have access to the Validator class in your controller you can simply call validate against your controller itself and set labels values in the view to show users messages. I personally don't like this approach because I think it is intrusive. An easy solution is displaying a tooltip and to do so we must have access to the control which value is invalid. The following code did this in our test application:

Method showValidationErrors gets the control that has an invalid value and set a tooltip for it

To show the tooltip we must have access to the control itself, and to do this we have to make some reflection, hence the field representing the control should be public or make get methods to access it

CDI, Bean Validation and JavaFX

There's nothing to add about CDI from what I have mentioned in Using CDI 2.0 in a JavaFX application post. I just wanted to share that the Hibernate Validator CDI API worked on a JavaFX application and due this I can simply inject the validator on my controller class! A single dependency will make that possible: org.hibernate.validator:hibernate-validator-cdi. See below the application files:

Our maven project and its files

And these are the dependencies I added to pom.xml:

These are all dependencies required to use bean validation and CDI on a JavaFX application

Code of a sample application can be found in github. Below you can see a quick video I made just to show what the validation with tooltips looks like:

Why this is important

Being able to integrate with Java EE (or should I say EE4J already?) is a key feature for users who want to build real world applications with JavaFX, it will bring persistence, validation, injection and more. The main question that remains here is: will it work on a Android application that uses Gluon/ JavaFX Ports?

For more Bean Validation specific examples you may check this Hendrik Ebbers pull request to hibernate validator project.

Nenhum comentário:

Postar um comentário