Property-based Converters

虽然 type-based conversion 已提供影响目标商店中某些类型的转换和表示的方法,但仅考虑特定类型的某些值或属性进行转换时,它存在局限性。基于属性的转换器允许基于每个属性配置转换规则,既可声明式(通过 @ValueConverter)也可编程方式(为特定属性注册 PropertyValueConverter)。

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).

PropertyValueConverter 可将给定值转换为其存储表示(写)并转换回来(读),如下列表所示。附加的 ValueConversionContext 提供附加信息,如映射元数据以及直接的 readwrite 方法。

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. .A simple PropertyValueConverter

/*
 * Copyright 2020-2024 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.data.cassandra.example;

// tag::class[]
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);
	}

	// end::class[]
	private String reverse(String source) {

		if (source == null) {
			return null;
		}

		return new StringBuilder(source).reverse().toString();
	}
	// tag::class[]
}
// end::class[]

您可以通过委托到 PropertyValueConversionsCustomConversions#getPropertyValueConverter(…) 获取 PropertyValueConverter 实例,通常情况下,通过使用 PropertyValueConverterFactory 提供实际的转换器。根据您的应用程序的需求,您可以链接或装饰 PropertyValueConverterFactory 的多个实例——例如,应用缓存。默认情况下,Spring Data Cassandra 使用一种可以处理具有默认构造函数或枚举值的类型的缓存实现。您可以通过 PropertyValueConverterFactory 中的工厂方法获得一组预定义的工厂。您可以使用 PropertyValueConverterFactory.beanFactoryAware(…)ApplicationContext 中获得 PropertyValueConverter 实例。

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.

可以通过 ConverterConfiguration 更改默认行为。

You can change the default behavior through ConverterConfiguration.

Declarative Value Converter

PropertyValueConverter 最直接的用法是使用 @ValueConverter 注释注释属性,该注释定义转换器类型:

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

Example 1. Declarative PropertyValueConverter
class Person {

  @ValueConverter(ReversingValueConverter.class)
  String ssn;
}

Programmatic Value Converter Registration

编程注册使用 PropertyValueConverterRegistrar 为实体模型中的属性注册 PropertyValueConverter 实例,如下例所示。声明注册和编程注册之间的区别在于编程注册完全在实体模型外部发生。如果您不能或不想对实体模型进行注释,这种方法很有用。

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 2. 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.

当注册转换器时,点表示法(如 registerConverter(Person.class, "address.street", …))用于在属性之间导航到嵌套对象时,将 not 受支持。

Dot notation (such as registerConverter(Person.class, "address.street", …)) for nagivating across properties into nested objects is not supported when registering converters.

仅当转换器是 PropertyValueConverter 类时,模式导出才能从注册转换器导出列类型。Lambda 无法确定泛型,使用 Lambda 将回退为属性类型。

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 提供了一个预类型 PropertyValueConverter 接口,它使用 CassandraConversionContext

CassandraValueConverter offers a pre-typed PropertyValueConverter interface that uses CassandraConversionContext.

CassandraCustomConversions configuration

默认情况下,CassandraCustomConversions 可以处理声明的值转换器,具体取决于配置的 PropertyValueConverterFactoryCassandraConverterConfigurationAdapter 帮助您设置编程值转换或定义要使用的 PropertyValueConverterFactory 或注册转换器。

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 3. 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) -> …);
  });
});