Vaadin Binder for MultiSelectComboBox

84 Views Asked by At

Can somebody please help me with Vaadin Binder for this `MultiSelectComboBox`.
Does the MultiSelectComboBox component, always requires a `Set` for the binding methods ?

I have such entity

@Entity(name = "recipes")
public class Recipe {

    // ...

    @Getter
    @Setter
    private List<Category> categories;

    // ...
}

My implementation of Binder for MultiSelectComboBox

private final Binder<Recipe> binder = new Binder<>(Recipe.class);
private final MultiSelectComboBox<Category> categoryMultiselect = new MultiSelectComboBox<>("Categories");

// ...

private void initBinder() {
    binder.forField(categoryMultiselect)
            .asRequired("Please fill this field")
            .withValidator(s -> !s.isEmpty(), "Please select at least one category")
            .withValidator(s -> s.size() <= 5, "Please select up to 5 categories")
            .bind(Recipe::getCategories, Recipe::setCategories);
}

Throws Incompatible types: Set<Category> is not convertible to List<Category>, as MultiSelectComboBox returns a Set and Recipe::getCategories returns a List<Category>.

Any ideas how can be this avoided ?
PS: I don't really want to change the List<Category> to Set<Category> in my Recipe.class.

2

There are 2 best solutions below

0
drialiyldrm On BEST ANSWER

You can convert Set to list using withConverter.

private void initBinder() {
Converter<Set<Category>, List<Category>> setToListConverter = new Converter<Set<Category>, List<Category>>() {
    @Override
    public Result<List<Category>> convertToModel(Set<Category> set, ValueContext context) {
        List<Category> list = new ArrayList<>(set);
        return Result.ok(list);
    }

    @Override
    public Set<Category> convertToPresentation(List<Category> list, ValueContext context) {
        Set<Category> set = new HashSet<>(list);
        return set;
    }
};

binder.forField(categoryMultiselect)
        .asRequired("Please fill this field")
        .withValidator(s -> !s.isEmpty(), "Please select at least one category")
        .withValidator(s -> s.size() <= 5, "Please select up to 5 categories")
        .withConverter(setToListConverter)
        .bind(Recipe::getCategories, Recipe::setCategories);}

(https://vaadin.com/docs/v23/binding-data/components-binder-validation#converting-user-input)

1
cfrick On

Yes, it always needs a Set, as this is part of its signature. This implies, that the items to select are unique to the selection, and they are unordered - both things, that a List can not promise -- whether this is actually important for the use-case is not clear.

So either switch to another component, that allows for ordering and duplicates -- or adopt between the Set and the List in your UI data class or in the binder (make sure your category is a good citizen for a Set (give it equals and hash-code) and deal with the order for your List by some means (e.g. add a priority to the category)).