Krótka notka dla wszystkich, którzy przesiedli się z JSF'a na Spring'a (wersja 2.5.6) i przyszło im użyć tagu
form:checkboxes. Idea obu tagów jest taka sama, czyli jak "przyjemnie" obsłużyć na formularzu wiele checkboxów.
Załóżmy, że mamy encje Employee i Language, które są w relacji wiele-do-wielu.
Aby wyświetlić na formularzu wszystkie checkboxy (języki) z zaznaczonymi tymi, które dany pracownik zna. W JSF używamy:
To samo w Spring'u wygląda następująco
Pominę kwestie skąd i jak wstrzykiwane są
allLanguages i
languages.
Wszystko teoretycznie powinno działać, ale niestety nie jest tak różowo. Pojawia się następujący błąd:
Failed to convert property value of type [java.lang.String] to required type [java.util.Set] for property languages; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [java.lang.String] to required type [emp.entity.Language] for property languages[0]: no matching editors or conversion strategy found
Przyczyną błędu jest brak odpowiedniego PropertyEditor'a dla Language. Przykładowy editor dla klasy Language:
public class LanguageEditor extends PropertyEditorSupport {
private LanguageManager languageManager;
public LanguageEditor(LanguageManager languageManager) {
super();
this.languageManager = languageManager;
}
@Override
public void setAsText(String text) throws IllegalArgumentException {
setValue(languageManager.getLanguageById(Long.parseLong(text)));
}
@Override
public String getAsText() {
Language language = (Language) getValue();
return language == null ? null : Long.toString(language.getId());
}
}
W moim przypadku metoda setAsText używa managera, który pobiera encje Language o danym id z bazy. Trzeba jeszcze tylko dodać tego editora w metodzie initBuilder w kontrolerze który odpowiada za obsługę formularzu:
public class EmployeeEditController extends SimpleFormController{
...
@Override
protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
super.initBinder(request, binder);
binder.registerCustomEditor(Language.class, new LanguageEditor(languageManager));
....
}
I coś takiego rozwiązuje zgłaszany błąd.