A Generic method to convert ResultSetFuture (of Datastax Java driver for Cassandra) to a list of table-row-model(POJO) for any table query

This post shows my new found love for CompletableFuture, lamdba expression and Streams API in Java.

Problem:

You do an async query on a table, get a ResultSetFuture object and need to populate a list of java objects representing a row in Cassandra table.

A normal way to do this would be

Assume: ResultSetFuture rsf = resultFromSomeTableQuery();

  1. ResultSet rs = rsf.get(); //get ResultSet from rsf
  2. get all rows as list by rs.all()
  3. now for each Row in above list create a new object(POJO/java object representing table row) and populate the new object by calling Row.get(column index) for each column.

This would lead to writing new code which does same task of converting ResultSetFuture to List of POJOs for each table query.

Solution:

I'll give my solution approach with an example.

Assumption:

Query:

SELECT id, name, age, city from population_keyspace.persons_table;

Corresponding Java object for table:


class Person{
    int id;
    String name;
    int age;
    String city;
}
        

The solution:

You need a method to convert ResultSetFuture object to CompletableFuture<List<Person>> :

CompletableFuture<List<Person>> result = resolveCassandraReadResultSetFuture(rsf, rowToPojo);

The above method takes two arguments:

  1. ResultSetFuture object - rsf
  2. Function object - rowToPojo

The rowToPojo function definition:

1
2
3
Function<Row, Person> rowToPojo = r -> {
    return new Person(r.getInt(0), r.getString(1), r.getInt(2), r.getString(3));
};

Explanation:

Above function takes a row, creates and returns a new Person object using the rows data.

The resolveCassandraReadResultSetFuture method definition:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
public static < T > CompletableFuture < List < T >> resolveCassandraReadResultSetFuture(ResultSetFuture rsf, Function < Row, T > rowToPojo) {

        Function < ResultSet, List < T >> readRS = s - > {
            List < Row > rows = s.all();
            return rows.
            stream().
            map(rowToPojo).
            collect(Collectors.toList());
        };

        CompletableFuture < List < T >> result = CompletableFuture.supplyAsync(() - > rsf.getUninterruptibly()).
        thenApply(readRS);

        return result;
    }

Explanation:

Above method contains a Function called readRS

readRS Function:

  1. readRS function takes a ResultSet s.
  2. Gets all rows as a list "rows" by s.all().
  3. Converts above list to stream.
  4. Maps each stream element to Person object using rowToPojo Function.
  5. Collects Person objects to a List<Person>

Inside resolveCassandraReadResultSetFuture method, call rsf.getUninterruptibly() to get CompletableFuture<ResultSet>
readRs will return a List<Person> which will be encapsulated in a CompletableFuture due to thenApply()

Conclusion:

Everytime you need to do a different query just write a rowToPojo Function and pass your ResultSetFuture object obtained by executing async query and your rowToPojo Function specific to that query to reaolveCassandraReadResultSetFuture method.

Peace

Comments

Popular posts from this blog

SelfAwarePotato

Converting google/guava ListenableFuture to Java 8 CompletableFuture