Firstly the main issue was that the Binder did not specify the generic type, it needed to be:
Binder<Food> binder = foodGrid.getEditor().getBinder();
And NOT what I had in my first post:
Binder binder = foodGrid.getEditor().getBinder();
That being said there were several other gotchas. First when you do a forField() you need to keep track of that binding to be able to set it later with the column. This wasn’t clear at all for me. Specifically you need to:
Binder.Binding<Food, Long> caloriesBinder = binder.forField(caloriesTextField)
.withValidator(CustomCaloryValidator::isValidValue, "Must be valid a positive amount")
.withConverter(new StringToCaloriesConverter("Must be an integer"))
.bind(Food::getCalories, Food::setCalories);
I’m not 100% sure on the caloriesBinder because my code is different and this is an example, but you need that binding. You then take that binding and do:
foodGrid.getColumn("calories").setEditorBinding(caloriesBinding);
This allows the correct editor to work. This is in the documentation but the example is very simple so I missed that. The other thing is that the documentation just seems to have Binding<Todo, Boolean> but that didn’t work for me, I had to do Binder.Binding<Todo, Boolean> for the example to work for me. Not sure why…
The next step which is extremely important depending on what you’re displaying, is to add a renderer otherwise you can run into some weird issues. For example if you’re using long to store a currency then you need to convert it to display a currency amount. Similarly if you’re using a date then you probably also want to format it. You then need to add a renderer. The only way I could find how to do it without compilation errors (mismatched types) was:
((Grid.Column<Food, Long>)foodGrid.getColumn("calories")).setRenderer(new CaloriesRenderer());
Just for completeness you then need to enable the editor with:
foodGrid.getEditor().setEnabled(true);
Lastly, if the table is part of a bigger bean then you need to call foodGrid.setItems(), you cannot just rely on binder.readBean() because it cannot accept a list. So for example if instead of food the bean was a meal which consisted of a number of ingredients, then you could not do binder.readBean(meal) nor could you do binder.readBean(meal.getIngredients) even though you can do binder.readBean(meal) for the rest of the form. The only way I could make it work was to do:
binder.readBean(meal);
foodGrid.setItems(meal.getIngredients);
I assume there’s a better way without needing both of these lines but I couldn’t find it…