Vaadin ComboBox: преобразование между строкой и POJO

Используя FieldGroup, у меня есть форма, связывающая все свойства Customer с помощью BeanItem<Customer> и отображающая их в FormLayout.

Мой класс Customer выглядит примерно так:

@Entity
@Table(name="customer")
public class Customer implements Serializable {
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private int id;

    private String description;
    (... other fields ...)

    private String language;
    (... getters and setters ...)
}

Свойство language является ярлыком для языка. Например "de", "en", "fr" и так далее.

Кроме того, есть класс POJO с именем Language (упрощенный код)

public class Language {
    protected String shortCut;

    public Language(String shortCut)
    {
        this.shortCut = shortCut;
    }

    public String getShortcut()
    {
        return this.shortCut;
    }
}

... и статический список экземпляров (упрощенный код):

public static List<Language> LANGUAGES = new ArrayList<>(Arrays.asList(new Language[]{
    new Language("de"),
    new Language("fr"),
    new Language("en")
}));

Наряду с данными клиента в макете формы я добавляю еще одно поле со списком, содержащее приведенный выше список языков.

Чего я хочу добиться, так это того, что при отправке формы язык, выбранный в поле со списком, берется, а его ярлык записывается в файл BeanItem. псевдокод:

// Assuming we have a combobox and our customer bean, both created before and elsewhere:
ComboBox cmbLanguage;
BeanItem<Customer> customer;

// Then, the language chosen by the user is:
Language lang = (Language)cmbLanguage.getValue();

// So this should actually happen upon saving the form:
customer.getItemProperty("language").setValue(lang.getShortcut());

Я знаю, что можно вручную изменить объект bean-компонента клиента, используя обработчик фиксации в группе полей. Но я хотел бы избежать этого.

Есть ли способ сделать это «автоматически», реализуя конвертер или тому подобное в поле со списком, форме или элементе bean-компонента?

Изучив N. Презентация Франкеля "Vaadin 7 FieldGroup & Converter" (страницы с 18 по 21), я пробовал использовать собственный экземпляр Converter. Но это, очевидно, не может работать, потому что связанное свойство не может быть одновременно набором/списком языков и языком клиента.

Как этого добиться?

Примечание. из-за совместимости я не могу изменить Customer, и мне нужно использовать конструкцию с языковым классом.


person Atmocreations    schedule 08.05.2014    source источник
comment
Не могли бы вы уточнить свой вопрос? Из описания непонятно, что вы пытаетесь сделать и зачем вам Convener, если вы просто пытаетесь связать поле со списком в сущности.   -  person user3551612    schedule 08.05.2014
comment
изменил мой вопрос. Надеюсь, теперь стало намного яснее.   -  person Atmocreations    schedule 08.05.2014


Ответы (2)


Если вам нужно ComboBox, которое дает вам значение Language, вы можете расширить класс ComboBox:

class LanguageComboBox extends ComboBox {
    public LanguageComboBox(String caption, Collection<Language> languages) {
        super(caption, getShortcuts(languages));
    }

    @Override
    public Language getValue() {
       return new Language((String) super.getValue());
    }

    private static List<String> getShortcuts(Collection<Language> languages) {
       // extract shortcuts using java 1.8 
       return languages.stream()
            .map(language -> language.getShortcut())
            .collect(Collectors.toList());
    }
}

а затем вы можете легко добавить это к FieldGroup с помощью BeanItem<Customer>:

    ComboBox comboBox = new LanguageComboBox("Language", LANGUAGES);
    fieldGroup.bind(comboBox,"language");

После отправки ваш клиент будет иметь правильное значение языка.

На мой взгляд, вы не должны использовать сущности в представлении - как вы упомянули, вы не можете изменить объект Customer, и, вероятно, этот класс содержит гораздо больше полей, которые вам нужны для вашего представления. Я бы предпочел создать отдельный класс POJO для этого представления - это даст вам гораздо больше гибкости, и не будет таких проблем, как вы сообщили. Конечно, в конце вам нужно преобразовать ваш объект просмотра в сущность или даже в несколько сущностей, но в большинстве случаев стоит нести эту цену.

person Arek Trzepacz    schedule 10.05.2014

Вы можете добавить значение ярлыка в качестве значения ComboBox и определить необязательный заголовок:

    cmbx.addContainerProperty("caption", String.class, "");
    cmbx.setItemCaptionPropertyId("caption");

    cmbx.addItem(languageEN.getLanguageShortCut()).getItemProperty("caption").setValue(languageEN.getLanguageLong());
    cmbx.addItem(languageFR.getLanguageShortCut()).getItemProperty("caption").setValue(languageFR.getLanguageLong());
person nexus    schedule 08.05.2014