Property-based Converters

While type-based conversion already offers ways to influence the conversion and representation of certain types within the target store, it has limitations when only certain values or properties of a particular type should be considered for conversion. Property-based converters allow configuring conversion rules on a per-property basis, either declaratively (via @ValueConverter) or programmatically (by registering a PropertyValueConverter for a specific property).

A PropertyValueConverter can transform a given value into its store representation (write) and back (read) as the following listing shows. The additional ValueConversionContext provides additional information, such as mapping metadata and direct read and write methods.

Example 1. A simple PropertyValueConverter
class ReversingValueConverter implements PropertyValueConverter<String, String, ValueConversionContext> {

	@Override
	public String read(String value, ValueConversionContext context) {
		return reverse(value);
	}

	@Override
	public String write(String value, ValueConversionContext context) {
		return reverse(value);
	}

}

You can obtain PropertyValueConverter instances from CustomConversions#getPropertyValueConverter(…) by delegating to PropertyValueConversions, typically by using a PropertyValueConverterFactory to provide the actual converter. Depending on your application’s needs, you can chain or decorate multiple instances of PropertyValueConverterFactory — for example, to apply caching. By default, Spring Data Cassandra uses a caching implementation that can serve types with a default constructor or enum values. A set of predefined factories is available through the factory methods in PropertyValueConverterFactory. You can use PropertyValueConverterFactory.beanFactoryAware(…) to obtain a PropertyValueConverter instance from an ApplicationContext.

You can change the default behavior through ConverterConfiguration.

Declarative Value Converter

The most straight forward usage of a PropertyValueConverter is by annotating properties with the @ValueConverter annotation that defines the converter type:

Example 2. Declarative PropertyValueConverter
class Person {

  @ValueConverter(ReversingValueConverter.class)
  String ssn;
}

Programmatic Value Converter Registration

Programmatic registration registers PropertyValueConverter instances for properties within an entity model by using a PropertyValueConverterRegistrar, as the following example shows. The difference between declarative registration and programmatic registration is that programmatic registration happens entirely outside the entity model. Such an approach is useful if you cannot or do not want to annotate the entity model.

Example 3. Programmatic PropertyValueConverter registration
PropertyValueConverterRegistrar registrar = new PropertyValueConverterRegistrar();

registrar.registerConverter(Address.class, "street", new PropertyValueConverter() { … }); (1)

// type safe registration
registrar.registerConverter(Person.class, Person::getSsn())                               (2)
  .writing(value -> encrypt(value))
  .reading(value -> decrypt(value));
1 Register a converter for the field identified by its name.
2 Type safe variant that allows to register a converter and its conversion functions. This method uses class proxies to determine the property. Make sure that neither the class nor the accessors are final as otherwise this approach doesn’t work.
Dot notation (such as registerConverter(Person.class, "address.street", …)) for nagivating across properties into nested objects is not supported when registering converters.
Schema derivation can only derive the column type from a registered converter if the converter is a PropertyValueConverter class. Generics cannot be determined from lambdas and using a lambda will fall back to the property type.
CassandraValueConverter offers a pre-typed PropertyValueConverter interface that uses CassandraConversionContext.

CassandraCustomConversions configuration

By default, CassandraCustomConversions can handle declarative value converters, depending on the configured PropertyValueConverterFactory. CassandraConverterConfigurationAdapter helps you to set up programmatic value conversions or define the PropertyValueConverterFactory to be used or to register converters.

Example 4. Configuration Sample
CassandraCustomConversions conversions = CassandraCustomConversions.create(adapter -> {
  adapter.registerConverter(…);
  adapter.configurePropertyConversions(registrar -> {
    registrar.registerConverter(Person.class, "name", String.class)
        .writing((from, ctx) -> …)
        .reading((from, ctx) -> …);
  });
});