© 2008-2014 The original authors.

Copies of this document may be made for your own use and for distribution to others, provided that you do not charge any fee for such copies and further provided that each copy contains this Copyright Notice, whether distributed in print or electronically.

Preface

1. Project metadata

Reference Documentation

2. Key Value Repositories

This chapter explains concepts and usage patterns when working with the key value abstraction and the java.util.Map based implementation provided by Spring Data Commons.

2.1. Core Concepts

The Key/Value abstraction within Spring Data Commons requires an Adapter shielding the native store implementation freeing up KeyValueTemplate to work on top of any key/value pair like structure. Keys are distributed across Keyspaces. Unless otherwise specified the class name is used as the default keyspace for an entity.

interface KeyValueOperations {

    <T> T insert(T objectToInsert);                               (1)

    void update(Object objectToUpdate);                           (2)

    void delete(Class<?> type);                                   (3)

    <T> T findById(Serializable id, Class<T> type);               (4)

    <T> Iterable<T> findAllOf(Class<T> type);                     (5)

    <T> Iterable<T> find(KeyValueQuery<?> query, Class<T> type);  (6)

    //... more functionality omitted.

}
1 Inserts the given entity and assigns id if required.
2 Updates the given entity.
3 Removes all entities of matching type.
4 Returns the entity of given type with matching id.
5 Returns all entities of matching type.
6 Returns a List of all entities of given type matching the criteria of the query.

2.2. Configuring The KeyValueTemplate

In its very basic shape the KeyValueTemplate uses a MapAdaper wrapping a ConcurrentHashMap using Spring Expression Language to perform queries and sorting.

The used KeyValueAdapter does the heavy lifting when it comes to storing and retrieving data. The data structure used will influence performance and/or multi threading behavior.

One may choose to use a different type or preinitialize the adapter with some values, and can do so using various constructors on MapKeyValueAdapter.

@Bean
public KeyValueOperations keyValueTemplate() {
  return new KeyValueTemplate(keyValueAdapter());
}

@Bean
public KeyValueAdapter keyValueAdapter() {
  return new MapKeyValueAdapter(ConcurrentHashMap.class);
}

2.3. Keyspaces

Keyspaces define in which part of the data structure the entity should be kept. So this is a rather similar concept as collections in MongoDB and Elasticsearch, Cores in Solr, Tables in JPA. By default the keyspace of an entity is extracted form its type, but one can also choose to store entities of different types within one keyspace. In that case any find operation will type check results.

@KeySpace("persons")
class Person {

  @Id String id;
  String firstname;
  String lastname;
}

class User extends Person {
  String username;
}

template.findAllOf(Person.class); (1)
template.findAllOf(User.class);   (2)
1 Returns all entities for keyspace "persons".
2 Returns only elements of type User stored in keyspace "persons".

2.3.1. Custom KeySpace Annotation

It is possible to compose own KeySpace annotations for a more domain centric usage by annotating one of the attibutes with @KeySpace.

The composed annotation needs to inherit @Persistent.
@Persistent
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
static @interface CacheCentricAnnotation {

  @KeySpace String cacheRegion() default "";
}

@CacheCentricAnnotation(cacheRegion = "customers")
class Customer {
  //...
}

2.4. Querying

Query execution is managed by the QueryEngine. As mentioned before it is possible to instruct the KeyValueAdapter to use an implementation specific QueryEngine that allows access to native functionality. When used without further customization queries are be executed using a SpELQueryEngine.

For performance reasons, we highly recommend to have at least Spring 4.1.2 or better to make use of compiled SpEL Expressions. Please use the -Dspring.expression.compiler.mode=IMMEDIATE switch to turn it on.
KeyValueQuery<String> query = new KeyValueQuery<String>("lastname == 'targaryen'");
List<Person> targaryens = template.find(query, Person.class);
Please note that you need to have getters/setters present to query properties using SpEL.

2.5. Sorting

Depending on the store implementation provided by the adapter entities might already be stored in some sorted way but do not necessarily have to be. Again the underlying QueryEngine is capable of performing sort operations. When used without further customization sorting is done using a SpelPropertyComperator extracted from the Sort clause provided

KeyValueQuery<String> query = new KeyValueQuery<String>("lastname == 'baratheon'");
query.setSort(new Sort(DESC, "age"));
List<Person> targaryens = template.find(query, Person.class);
Please note that you need to have getters/setters present to sort using SpEL.

2.6. Map Repositories

Map repositories reside on top of the KeyValaueTemplate. Using the default SpelQueryCreator allows deriving query and sort expressions from the given methodname.

@Configuration
@EnableMapRepositories
class KeyValueConfig {

}

interface PersonRepository implements CrudRepository<Person, String> {
    List<Person> findByLastname(String lastname);
}

Appendix