Vaadin Beginner - Help needed

Hi,

I’m following Vaadin’s tutorial: https://vaadin.com/docs/v8/framework/tutorial.html

In step 6, creating a from using plain Java, I’m having the following problem: Caused by: java.lang.IllegalStateException: Unable to detect value type for the member ‘status’ in the class ‘com.jetbrains.CustomerForm’.

Here, I’m basically trying to create a form, where its form fields will correspond to a Customer instance that is selected (via Binder class)

The issue seems to come from the code binder.bindInstanceFields(this);. Everything seems to work if I comment out this code.

Note: the status field is an enum defined within CustomerStatus (below)

CustomerForm: import com.vaadin.event.ShortcutAction; import com.vaadin.ui.FormLayout; import com.vaadin.ui.NativeSelect; import com.vaadin.ui.*; import com.vaadin.ui.themes.ValoTheme; import com.vaadin.data.Binder;

public class CustomerForm extends FormLayout {
    private TextField firstName = new TextField("First Name");
    private TextField lastName = new TextField("Last Name");
    private DateField birthDate = new DateField("Birthday");
    private NativeSelect status = new NativeSelect("Status");
    private TextField email = new TextField("Email");
    private Button save = new Button("Save");
    private Button delete = new Button("Delete");
    private Binder<Customer> binder = new Binder<>(Customer.class);

    private CustomerService service = CustomerService.getInstance();
    private Customer customer;
    private MyUI myUI;

    public CustomerForm(MyUI myUI) {
        this.myUI = myUI;

        setSizeUndefined();
        HorizontalLayout buttons = new HorizontalLayout(save, delete);
        addComponents(firstName, lastName, birthDate, status, email, buttons);

        status.setItems(CustomerStatus.values());
        save.setStyleName(ValoTheme.BUTTON_PRIMARY);
        save.setClickShortcut(ShortcutAction.KeyCode.ENTER);

        binder.bindInstanceFields(this);

        save.addClickListener(e -> save());
        delete.addClickListener(e -> delete());
    }

    public void setCustomer(Customer customer) {
        this.customer = customer;
        binder.setBean(customer);

        delete.setVisible(customer.isPersisted());
        setVisible(true);
        firstName.selectAll();
    }

    private void save() {
        service.save(customer);
        myUI.updateList();
        setVisible(false);
    }

    private void delete() {
        service.delete(customer);
        myUI.updateList();
        setVisible(false);
    }
}

MyUI:

public class MyUI extends UI {

    private CustomerService service = CustomerService.getInstance();
    private Grid<Customer> grid = new Grid<>(Customer.class);
    private TextField filterText = new TextField();
    private CustomerForm form = new CustomerForm(this);

    @Override
    protected void init(VaadinRequest vaadinRequest) {
        final VerticalLayout layout = new VerticalLayout();

        filterText.setPlaceholder("Filter by name...");
        filterText.setValueChangeMode(ValueChangeMode.LAZY);
        filterText.addValueChangeListener(e -> updateList());

        Button clearFilterTextBtn = new Button(VaadinIcons.CLOSE);
        clearFilterTextBtn.addClickListener(e -> filterText.clear());
        clearFilterTextBtn.setDescription("Clear filter text");

        CssLayout filtering = new CssLayout();
        filtering.addComponents(filterText, clearFilterTextBtn);
        filtering.setStyleName(ValoTheme.LAYOUT_COMPONENT_GROUP);

        grid.setColumns("firstName", "lastName", "email", "status");

        HorizontalLayout main = new HorizontalLayout(grid, form);
        main.setSizeFull();
        grid.setSizeFull();
        main.setExpandRatio(grid, 1);


        layout.addComponents(filtering, main);

        updateList();

        setContent(layout);

        form.setVisible(false);
        grid.asSingleSelect().addValueChangeListener(event -> {
            if(event.getValue() == null) {
                form.setVisible(false);
            } else {
                form.setCustomer(event.getValue());
            }
        });
    }

    public void updateList() {
        List<Customer> customers = service.findAll(filterText.getValue());
        grid.setItems(customers);
    }

    @WebServlet(urlPatterns = "/*", name = "MyUIServlet", asyncSupported = true)
    @VaadinServletConfiguration(ui = MyUI.class, productionMode = false)
    public static class MyUIServlet extends VaadinServlet {
    }
}

Customer:

import java.io.Serializable;
import java.time.LocalDate;
import java.util.Date;

/**
 * A entity object, like in any other Java application. In a typical real world
 * application this could for example be a JPA entity.
 */
@SuppressWarnings("serial")
public class Customer implements Serializable, Cloneable {

    private Long id;

    private String firstName = "";

    private String lastName = "";

    private LocalDate birthDate;

    private CustomerStatus status;

    private String email = "";

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    /**
     * Get the value of email
     *
     * @return the value of email
     */
    public String getEmail() {
        return email;
    }

    /**
     * Set the value of email
     *
     * @param email
     *            new value of email
     */
    public void setEmail(String email) {
        this.email = email;
    }

    /**
     * Get the value of status
     *
     * @return the value of status
     */
    public CustomerStatus getStatus() {
        return status;
    }

    /**
     * Set the value of status
     *
     * @param status
     *            new value of status
     */
    public void setStatus(CustomerStatus status) {
        this.status = status;
    }

    /**
     * Get the value of birthDate
     *
     * @return the value of birthDate
     */
    public LocalDate getBirthDate() {
        return birthDate;
    }

    /**
     * Set the value of birthDate
     *
     * @param birthDate
     *            new value of birthDate
     */
    public void setBirthDate(LocalDate birthDate) {
        this.birthDate = birthDate;
    }

    /**
     * Get the value of lastName
     *
     * @return the value of lastName
     */
    public String getLastName() {
        return lastName;
    }

    /**
     * Set the value of lastName
     *
     * @param lastName
     *            new value of lastName
     */
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    /**
     * Get the value of firstName
     *
     * @return the value of firstName
     */
    public String getFirstName() {
        return firstName;
    }

    /**
     * Set the value of firstName
     *
     * @param firstName
     *            new value of firstName
     */
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public boolean isPersisted() {
        return id != null;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (this.id == null) {
            return false;
        }

        if (obj instanceof Customer && obj.getClass().equals(getClass())) {
            return this.id.equals(((Customer) obj).id);
        }

        return false;
    }

    @Override
    public int hashCode() {
        int hash = 5;
        hash = 43 * hash + (id == null ? 0 : id.hashCode());
        return hash;
    }

    @Override
    public Customer clone() throws CloneNotSupportedException {
        return (Customer) super.clone();
    }

    @Override
    public String toString() {
        return firstName + " " + lastName;
    }
}

CustomerStatus:

public enum CustomerStatus {
    ImportedLead, NotContacted, Contacted, Customer, ClosedLost
}

Hi,

I think it’s because you didn’t set the type of the NativeSelect. Can you try this?

private NativeSelect<CustomerStatus> status = new NativeSelect<>("Status");

You said that you are starting to learn Vaadin, is there any reason for using Vaadin 8 instead of Vaadin 14?