Blog

Lazy loading with Vaadin 8

By  
Alejandro Duarte
Alejandro Duarte
·
On Mar 20, 2017 8:26:00 AM
·

One of my favorite new features in Vaadin 8 is the Grid::setDataProvider method which makes it remarkably easy to implement lazy loading in Grids. In earlier versions of Vaadin, you had to implement a rather complex Container interface. Vaadin 8 not only removes this interface, but also provides a modern API that takes advantage of many Java 8 features.

In this blog post, you will learn how to implement lazy loading to show a sortable list of people in a Grid component by simply providing two lambda expressions. You can find two “flavors” of the example application: One for people who use Spring (Spring Boot), and one for people who use Java EE (CDI and WildFly Swarm):

What is lazy loading?

Lazy loading is a technique used to delay the loading of resources to the point where it’s actually needed. Say you have a database table with 1000 rows, and you want to show this data in a UI with space for 20 rows at a time. You can query just the first 20 rows and when the user scrolls down the list, then you query the next 20 rows, and so forth. If you fetch all the data from your data source, your app will consume more memory and will take longer to show something on the screen.

When you want to display tons of data, you would probably use Vaadin’s Grid. By default, Grid performs lazy loading between the client and the server, which already improves performance a lot. This means that you have lazy loading out-of-the-box between the Grid component (in the browser) and the web server. How you query your data source is entirely up to you. If you try to fetch all the data at once, then the Grid will only send what’s needed when it’s needed to the client. However, all the data will stay in the memory on the server-side. Fortunately, the Grid class provides the mechanisms to allow you to query your data source in a lazy way. Let’s see how to do it!

The domain model

Suppose you have a domain class like the following:

public class Person {

    private Long id;
    private String firstName;
    private String lastName;
    private String email;

    ... getter and setters ...
}

And a service class like this:

public class PersonService {

    public List<Person> findAll(int offset, int limit) {
        ...
    }

    public int count() {
        ...
    }
}
 

The actual implementation of the methods depends on your specific persistence technologies. You can find a full implementation of the Person and PersonService classes for both Spring and Java EE applications using the links provided in the introduction.

Lazy loading functionality with Grid

You obviously need an instance of the PersonService class and a new Grid:

PersonService service = new PersonService();
Grid<Person> grid = new Grid<>(Person.class);

Notice how, in Vaadin 8, Grid is parameterized with the domain type (Person). Now, instead of using the infamous grid.setItems(service.findAll()), you can use the setDataProvider method and pass:

  1. A lambda expression to return a “slice” of the data and,

  2. Another lambda expression to return the total count of people in the data source.

You can delegate these operations to the service class:

grid.setDataProvider(
    (sortOrders, offset, limit) ->
            service.findAll(offset, limit).stream(),
    () -> service.count()
);

Ordering functionality

If you read the previous snippet of code, you might have noticed the sortOrders parameter in the first lambda expression. sortOrder is a List of QuerySortOrder objects that you can use to tell your service how to order the data.

The PersonService::findAll method accepts a Map with String keys representing the name of a Java property in the Person class, and a Boolean value telling whether to sort the property in ascending order. So, for this example, you have to translate between a List<QuerySortOrder> and a Map<String, Boolean>). Some Java should do the job:

Map<String, Boolean> sortOrder = new LinkedHashMap<>();

for (QuerySortOrder order : sortOrders) {
    sortOrder.put(order.getSorted(),
            SortDirection.ASCENDING.equals(order.getDirection()));
}

As you can see, the QuerySortOrder::getSorted method returns a string with the name of the Java property, and the SortOrder::getDirection method (QuerySortOrder extends SortOrder) returns a value from the SortDirection enum.

And that’s it! You can pass this map to the service, so the complete call to the setDataProvider method would look like this:

grid.setDataProvider(
    (sortOrders, offset, limit) -> {
        Map<String, Boolean> sortOrder = sortOrders.stream()
                .collect(Collectors.toMap(
                        sort -> sort.getSorted(),
                        sort -> SortDirection.ASCENDING.equals(
                                sort.getDirection())));

        return service.findAll(offset, limit, sortOrder).stream();
    },
    () -> service.count()
);

Learn more about Vaadin 8

Alejandro Duarte
Alejandro Duarte
Software Engineer and Developer Advocate at MariaDB Corporation. Author of Practical Vaadin (Apress), Data-Centric Applications with Vaadin 8 (Packt), and Vaadin 7 UI Design by Example (Packt). Passionate about software development with Java and open-source technologies. Contact him on Twitter @alejandro_du or through his personal blog at www.programmingbrain.com.
Other posts by Alejandro Duarte