CommitException Property not bound to datasource - need help

I am new to Vaadin and on a tight deadline so I am hoping someone can help me understand what is going on here. I have a form and using BeanFieldGroup but when I call commit it blows up with com.vaadin.data.fieldgroup.FieldGroup$CommitException: Property “brand” not bound to datasource.

This is my backing object.

public class ParameterFormDto {

private Brand brand;
private Category category;
private SubCategory subCategory;
private MasterParameter masterParameter;
private ParameterLevel parameterLevel;
private String levelValue;
private String order;
private String value;
private Date effectiveStartDate;
private Date effectiveEndDate;

public ParameterFormDto() {

}

public Brand getBrand() {
return brand;
}

public void setBrand(Brand brand) {
this.brand = brand;
}

public Category getCategory() {
return category;
}

public void setCategory(Category category) {
this.category = category;
}

public SubCategory getSubCategory() {
return subCategory;
}

public void setSubCategory(SubCategory subCategory) {
this.subCategory = subCategory;
}

public MasterParameter getMasterParameter() {
return masterParameter;
}

public void setMasterParameter(MasterParameter masterParameter) {
this.masterParameter = masterParameter;
}

public ParameterLevel getParameterLevel() {
return parameterLevel;
}

public void setParameterLevel(ParameterLevel parameterLevel) {
this.parameterLevel = parameterLevel;
}

public String getLevelValue() {
return levelValue;
}

public void setLevelValue(String levelValue) {
this.levelValue = levelValue;
}

public String getOrder() {
return order;
}

public void setOrder(String order) {
this.order = order;
}

public String getValue() {
return value;
}

public void setValue(String value) {
this.value = value;
}

public Date getEffectiveStartDate() {
return effectiveStartDate;
}

public void setEffectiveStartDate(Date effectiveStartDate) {
this.effectiveStartDate = effectiveStartDate;
}

public Date getEffectiveEndDate() {
return effectiveEndDate;
}

public void setEffectiveEndDate(Date effectiveEndDate) {
this.effectiveEndDate = effectiveEndDate;
}
}

And this is my form code.

@SpringComponent
@UIScope
public class AddParameterForm extends FormLayout {

private static final Logger logger = LoggerFactory.getLogger(AddParameterForm.class);

private final ParameterService parameterService;

private BeanFieldGroup<ParameterFormDto> formFieldBindings = new BeanFieldGroup<>(ParameterFormDto.class);

// ui memebers
@PropertyId("brand")
public NativeSelect brand;
private NativeSelect category;
private NativeSelect subCategory;
private NativeSelect parameter;
private NativeSelect level;
private TextField levelValue;
private TextField order;
private TextField value;
private PopupDateField effectiveStart;
private PopupDateField effectiveEnd;
private Button cancelButton;
private Button saveButton;

// data members
private Brand selectedBrand;
private Category selectedCategory;
private SubCategory selectedSubCategory;
private MasterParameter selectedParameter;
private ParameterLevel selectedParameterLevel;

@Autowired
public AddParameterForm(ParameterService parameterService) {
    this.parameterService = parameterService;
    initUserInterface();
}

private void initUserInterface() {

    setVisible(false);
    setMargin(true);
    setSizeFull();

    //formFieldBindings = new BeanFieldGroup<>(ParameterFormDto.class);

    // initialize ui components
    brand = new NativeSelect("Brand");
    brand.setEnabled(true);
    category = new NativeSelect("Category");
    category.setEnabled(false);
    subCategory = new NativeSelect("Sub Category");
    subCategory.setEnabled(false);
    parameter = new NativeSelect("Parameter");
    parameter.setEnabled(false);
    level = new NativeSelect("Level");
    level.setEnabled(false);
    levelValue = new TextField("Level Value");
    order = new TextField("Order");
    value = new TextField("Value");
    effectiveStart = new PopupDateField("Effective Start");
    effectiveEnd = new PopupDateField("Effective End");
    cancelButton = new Button("Cancel", event -> {
        logger.debug("user cancelled adding parameter");
        formFieldBindings.discard();
        setVisible(false);
        closeParentWindow();
        Notification.show("Cancelled", Notification.Type.TRAY_NOTIFICATION);
    });
    saveButton = new Button("Save", event -> {
        try {
            formFieldBindings.commit();
            ParameterFormDto parameter = formFieldBindings.getItemDataSource().getBean();
            parameterService.save(parameter);
            setVisible(false);
            closeParentWindow();
            Notification.show("Parameter saved successfully", Notification.Type.TRAY_NOTIFICATION);
        }
        catch (FieldGroup.CommitException e) {
            Notification.show("Error while saving parameter", Notification.Type.ERROR_MESSAGE);
            logger.error("Error saving parameter", e);
        }
    });

    effectiveStart.setDateFormat("MM/dd/yyyy HH:mm");
    effectiveStart.setResolution(Resolution.MINUTE);

    effectiveEnd.setDateFormat("MM/dd/yyyy HH:mm");
    effectiveEnd.setResolution(Resolution.MINUTE);

    // validation logic
    effectiveStart.addValidator((Validator) value1 -> {
        if (value1 == null) {
            throw new Validator.InvalidValueException("Effective Start Time cannot be null");
        }
        try {

            java.util.Calendar cal = java.util.Calendar.getInstance();
            cal.setTime((Date) value1);
        } catch (Exception e) {
            throw new Validator.InvalidValueException("Effective Start Time is invalid");
        }

    });
    order.addValidator(value1 -> {
        if (value1 == null) {
            throw new Validator.EmptyValueException("Order cannot be blank");
        }
        //if (Integer.parseInt((String) value1) < 0) {
        //    throw new Validator.InvalidValueException("Order can't be negative");
        //}
    });
    value.addValidator(value1 -> {
        if (value1 == null || value1.equals("")) {
            throw new Validator.EmptyValueException("Please provide a parameter value");
        }
    });
    levelValue.addValidator(value1 -> {
        if (value1 == null || value1.equals("")) {
            throw new Validator.EmptyValueException("Please provide a level value");
        }
    });
    effectiveEnd.addValidator(value1 -> {
        if (value1 != null) {
            java.util.Calendar today = java.util.Calendar.getInstance();
            today.set(java.util.Calendar.MINUTE, 0);
            today.set(java.util.Calendar.SECOND, 0);
            today.set(java.util.Calendar.HOUR_OF_DAY, 0);
            if (((Date) value1).getTime() < today.getTimeInMillis()) {
                throw new Validator.InvalidValueException("Effective end time cannot be in the past");
            }
        }
    });

    BeanItemContainer<Brand> brandBeanItemContainer =
            new BeanItemContainer<Brand>(Brand.class, parameterService.getBrands());
    BeanItemContainer<Category> categoryBeanItemContainer =
            new BeanItemContainer<Category>(Category.class, parameterService.getCategories());
    BeanItemContainer<ParameterLevel> parameterLevelBeanItemContainer =
            new BeanItemContainer<ParameterLevel>(ParameterLevel.class, parameterService.getLevels());

    level.setContainerDataSource(parameterLevelBeanItemContainer);
    level.setItemCaptionPropertyId("level");
    level.addValueChangeListener(event -> {
        ParameterLevel parameterLevel = (ParameterLevel) event.getProperty().getValue();
        if (parameterLevel != null && parameterLevel.getId() == 1) {
            levelValue.setValue("ANY");
            levelValue.setReadOnly(true);
        }
        else if (parameterLevel != null && parameterLevel.getId() > 1) {
            levelValue.setReadOnly(false);
            levelValue.setValue("");
        }
    });

    brand.setContainerDataSource(brandBeanItemContainer);
    brand.setItemCaptionPropertyId("name");
    brand.addValueChangeListener(event -> {
        selectedBrand = (Brand) event.getProperty().getValue();
        if (selectedBrand != null) {
            category.setEnabled(true);
            category.setContainerDataSource(categoryBeanItemContainer);
            category.setItemCaptionPropertyId("category");
        }
    });

    category.addValueChangeListener(event -> {
        selectedCategory = (Category) event.getProperty().getValue();
        if (selectedCategory != null) {
            subCategory.setEnabled(true);
            BeanItemContainer<SubCategory> subCategoryBeanItemContainer =
                    new BeanItemContainer<SubCategory>(SubCategory.class,
                            parameterService.getSubCategories(selectedCategory.getId()));
            subCategory.setContainerDataSource(subCategoryBeanItemContainer);
            subCategory.setItemCaptionPropertyId("subCategory");
        }
    });

    subCategory.addValueChangeListener(event -> {
        selectedSubCategory = (SubCategory) event.getProperty().getValue();
        if (selectedSubCategory != null) {
            parameter.setEnabled(true);
            BeanItemContainer<MasterParameter> masterParameterBeanItemContainer =
                    new BeanItemContainer<MasterParameter>(MasterParameter.class,
                            parameterService.getMasterParam(selectedBrand.getId(), selectedSubCategory.getId()));
            parameter.setContainerDataSource(masterParameterBeanItemContainer);
            parameter.setItemCaptionPropertyId("parameterName");
        }
    });

    parameter.addValueChangeListener(event -> {
        selectedParameter = (MasterParameter) event.getProperty().getValue();
        if (selectedParameter != null) {
            level.setEnabled(true);
            order.setEnabled(true);
            value.setEnabled(true);
            effectiveStart.setEnabled(true);
            effectiveEnd.setEnabled(true);
        }
    });

    formFieldBindings.buildAndBindMemberFields(this);
    addComponent(brand);
    addComponent(category);
    addComponent(subCategory);
    addComponent(parameter);
    addComponent(level);
    addComponent(levelValue);
    addComponent(order);
    addComponent(value);
    addComponent(effectiveStart);
    addComponent(effectiveEnd);
    HorizontalLayout horizontalLayout = new HorizontalLayout(saveButton, cancelButton);
    horizontalLayout.setSpacing(true);
    horizontalLayout.setMargin(false);
    addComponent(horizontalLayout);
    brand.focus();
}

@Override
public MainUI getUI() {
    return (MainUI) super.getUI();
}

private void closeParentWindow() {
    ((AddParameterWindow) super.getParent().getParent()).close();
}

}

You seem to be missing the formFieldBindings.setItemDataSource() call.

I’m confused what I would pass it in this context. I think what is making this complicated is all my NativeSelect objects are bound to a POJO instead of an enum or String. Is there a example of how to accomplish this?

formFieldBindings.setItemDataSource(new ParameterFormDto());

That seemed to work!!!

It’s perfectly fine to bind to a POJO. The selected value of the select will be the POJO itself, so it works. The only thing to look out for is that you need to either a) have a toString() in your POJO or b) manually set the caption for the items in order to get human readable alternatives.

Thanks for the help! I was stuck on that for a good day. This is a really cool framework once you get into it!

Thanks! Glad I could help.

It looks like you could also simplify your code a bit by using setRequired() instead of manually checking for empty values in some of those fields.