Skip to content

Validation of excluded properties #178

@oova

Description

@oova

Hi,
my question might be better asked on SO but from my experience FXForm2-related questions on SO do not get a lot of feedback, so I'm asking here.

I would like to add or remove an ExcludeFilter to/from my form depending on the state of a property. This is my sample code:

import com.dooapp.fxform.FXForm;
import com.dooapp.fxform.annotation.Accessor;
import com.dooapp.fxform.filter.ExcludeFilter;

import org.hibernate.validator.constraints.NotBlank;

import javafx.application.Application;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;

public class FilteredForm extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        MyBean bean = new MyBean();
        FXForm<MyBean> form = new FXForm<>();
        form.setSource(bean);

        Pane root = new Pane(form);
        Scene scene = new Scene(root, 800, 600);
        primaryStage.setScene(scene);
        primaryStage.show();

        ExcludeFilter commentExclusion = new ExcludeFilter("comment");
        bean.commentEnabled.addListener((obs, oldValue, newValue) -> {
            if (newValue) {
                form.getFilters().remove(commentExclusion);
            } else {
                form.addFilters(commentExclusion);
            }
        });
    }

    @Accessor(value = Accessor.AccessType.METHOD)
    public static class MyBean {

        private BooleanProperty commentEnabled = new SimpleBooleanProperty(this, "commentEnabled", true);
        private IntegerProperty priority = new SimpleIntegerProperty(this, "priority", 1);
        private StringProperty comment = new SimpleStringProperty(this, "comment", "");

        public boolean isCommentEnabled() {
            return commentEnabled.get();
        }

        public BooleanProperty commentEnabledProperty() {
            return commentEnabled;
        }

        public int getPriority() {
            return priority.get();
        }

        public void setPriority(int priority) {
            this.priority.set(priority);
        }

        public IntegerProperty priorityProperty() {
            return priority;
        }

        @NotBlank
        public String getComment() {
            return comment.get();
        }

        public void setComment(String comment) {
            this.comment.set(comment);
        }

        public StringProperty commentProperty() {
            return comment;
        }
    }

}

When I run this application, the commentEnabled check box will be selected and the comment text field is shown. When I unselect, the comment text field is gone. When I select again, I see the following null pointer exception:

Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
	at com.dooapp.fxform.controller.PropertyEditorController.updateView(PropertyEditorController.java:112)
	at com.dooapp.fxform.controller.PropertyEditorController.access$300(PropertyEditorController.java:38)
	at com.dooapp.fxform.controller.PropertyEditorController$2.changed(PropertyEditorController.java:97)
	at com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:361)
	at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
	at javafx.beans.property.BooleanPropertyBase.fireValueChangedEvent(BooleanPropertyBase.java:103)
	at javafx.beans.property.BooleanPropertyBase.markInvalid(BooleanPropertyBase.java:110)
	at javafx.beans.property.BooleanPropertyBase.set(BooleanPropertyBase.java:144)
	at javafx.beans.property.BooleanProperty.setValue(BooleanProperty.java:81)
	at javafx.beans.property.BooleanPropertyBase.setValue(BooleanPropertyBase.java:49)
	at com.dooapp.fxform.model.impl.PropertyMethodElement.setValue(PropertyMethodElement.java:35)
	at com.dooapp.fxform.controller.PropertyEditorController$1.changed(PropertyEditorController.java:81)
	at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:182)
	at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
	at javafx.beans.property.BooleanPropertyBase.fireValueChangedEvent(BooleanPropertyBase.java:103)
	at javafx.beans.property.BooleanPropertyBase.markInvalid(BooleanPropertyBase.java:110)
	at javafx.beans.property.BooleanPropertyBase.set(BooleanPropertyBase.java:144)
	at javafx.scene.control.CheckBox.setSelected(CheckBox.java:156)
	at javafx.scene.control.CheckBox.fire(CheckBox.java:236)
	at com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:182)
	at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:96)
	at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:89)
	at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
	at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
	at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
	at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
	at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
	at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
	at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
	at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
	at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
	at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
	at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
	at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
	at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
	at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
	at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
	at javafx.event.Event.fireEvent(Event.java:198)
	at javafx.scene.Scene$MouseHandler.process(Scene.java:3757)
	at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485)
	at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
	at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494)
	at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:394)
	at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:295)
	at java.security.AccessController.doPrivileged(Native Method)
	at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$353(GlassViewEventHandler.java:432)
	at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
	at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:431)
	at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
	at com.sun.glass.ui.View.notifyMouse(View.java:937)
	at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
	at com.sun.glass.ui.win.WinApplication.lambda$null$147(WinApplication.java:177)
	at java.lang.Thread.run(Thread.java:748)

I can ignore the exception, but there is another issue (or feature?): the comment property is validated although it is not shown in the form. If I leave the comment field empty (and the check box unselected), the form's list of constraint violations contains the 'not blank' violation from the comment property, and form.isValid() returns false. This is because the validation takes place on the bean, not on the form, I assume, but I find this slightly confusing as the form itself looks valid to the user when its internal state is not.

I think it is possible to filter the constraint violations accordingly such that the form internal validation's state would match the state presented in the GUI, but I'm wondering if this would be the correct approach. So my questions are:

  • Is the existing behaviour the intended behaviour?
  • Is using a (dynamic) exclusion filter the right approach for this use case? (the NPE might suggest otherwise)
  • Could filters be taken into account by FXForm when validating form elements? This might require FXForm to trigger a re-validation of all properties when one property changes as we do not know which property had a new filter attached.

I'd appreciate any feedback or hints to things I have overlooked or misunderstood. Thank you.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions