Gorge Tor
Gorge Tor

Reputation: 73

Show data from SQL in Vaadin Grid

I am trying to show my SQL table data in my Grid but nothing seems to work. Can you point me where i was wrong?

I found so many ways in the internet, but none have worked for me. Hope you can find the problem and assist me.

I'm using: Vaadin 14 with Spring boot

CustomerService.java

@Component
public class CustomerService {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    public List<Customer> findAll() {
        return jdbcTemplate.query(
                "SELECT ID, FirstName, LastName FROM customer",
                (rs, rowNum) -> new Customer(rs.getLong("id"),
                        rs.getString("First Name"), rs.getString("Last Name")));
    }

    public void update(Customer customer) {
        jdbcTemplate.update("INSERT INTO customer (FirstName,LastName) VALUES(?,?)",customer.getFirstName(),customer.getLastName());


    }
}

MainView.Java

public class MainView extends VerticalLayout {
    @Autowired
    private CustomerService service ;
    public Customer customer = new Customer();
    private Binder<Customer> binder = new Binder<>(Customer.class);
    private TextField firstName = new TextField("First name");
    private TextField lastName = new TextField("Last name");

    private Grid<Customer> grid = new Grid(Customer.class);
    private  Button save = new Button("Save", e -> {
        try {
            binder.writeBean(customer);
            saveCustomer();
            binder.readBean(new Customer());
        } catch (ValidationException ex) {
            ex.printStackTrace();
        }
    });

    public MainView(CustomerService service) {
       add(
                new H1("הוסף לקוח"),
               buildForm(),
               grid
       );
       updateGrid(); // update the grid with the sql data

        setSizeFull();


    }
    private void saveCustomer() throws ValidationException {

        service.update(customer);

    }
    private Component buildForm() {

       // TextField id = new TextField("ID");
        TextField firstName = new TextField("First name");
         TextField lastName = new TextField("Last name");
        Div errorsLayout = new Div();

binder.forField(firstName)
        .bind(
                Customer::getFirstName,Customer::setFirstName
        );
        binder.forField(lastName)
                .bind(
                        Customer::getLastName,Customer::setLastName
                );



        Button reload = new Button("reload", e ->{
            try{
                binder.readBean(customer);
               
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        });
        // Configure UI components
        save.setThemeName("primary");
        // Wrap components in layouts
        HorizontalLayout formLayout = new HorizontalLayout(grid,firstName,lastName,save,reload);
        Div wrapperLayout = new Div(formLayout, errorsLayout);
        formLayout.setDefaultVerticalComponentAlignment(Alignment.BASELINE);
        wrapperLayout.setWidth("100%");

        grid.setColumnReorderingAllowed(true);

        
        return wrapperLayout;

    }


    private void updateGrid() {
        List<Customer> customers = service.findAll();
        grid.setItems(customers);



    }

The error I get:

There was an exception while trying to navigate to '' with the exception message 'Error creating bean with name 'com.packagename.myapp.spring.MainView': Bean instantiation via constructor failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.packagename.myapp.spring.MainView]: Constructor threw exception; nested exception is java.lang.NullPointerException'

Upvotes: 0

Views: 253

Answers (1)

Erik Lumme
Erik Lumme

Reputation: 5342

You're never setting your CustomerService field. Add

this.service = service;

to the beginning of your constructor. Otherwise the member field private CustomerService service will be null, which is why updateGrid throws a NullPointerException.

Also, as a side note, remove the @Autowired annotation from the member field. Your mixing two different ways of autowiring, one is autowiring fields

@Autowired
private CustomerService service;

public MainView() { ... }

In this case, Spring will automatically set the value for you, and it is not passed as an argument to the constructor. However, Spring sets it after the constructor, so you can not use it in the constructor or any method called from the constructor.

The other way is constructor autowiring, which is what you should be doing. In this case Spring passes the bean to the constructor, but you need to set member fields yourself if needed.

private CustomerService service;

@Autowired
public MainView(CustomerService service) {
    this.service = service;
    ...
}

You don't strictly need the @Autowired annotation before the constructor, it will work without it, but you can have it there for clarity if you want.

Upvotes: 2

Related Questions