Overriding Default Mapping with Custom Converters
Custom Conversions
Spring Converter
实现的以下示例将 String
转换为自定义 Email
值对象:
The following example of a Spring Converter
implementation converts from a String
to a custom Email
value object:
@ReadingConverter
public class EmailReadConverter implements Converter<String, Email> {
public Email convert(String source) {
return Email.valueOf(source);
}
}
如果您编写一个其源类型和目标类型都是本机类型的 Converter
,我们将无法确定是否应该将其视为读转换器还是写转换器。将转换器实例同时注册为两个实例可能会导致意外结果。例如,Converter<String, Long>
是有歧义的,尽管在编写时尝试将所有 String
实例转换为 Long
实例可能没有意义。为了强制基础设施仅为单向注册一个转换器,我们提供 @ReadingConverter
和 @WritingConverter
注释在转换器实现中使用。
If you write a Converter
whose source and target type are native types, we cannot determine whether we should consider it as a reading or a writing converter.
Registering the converter instance as both might lead to unwanted results.
For example, a Converter<String, Long>
is ambiguous, although it probably does not make sense to try to convert all String
instances into Long
instances when writing.
To let you force the infrastructure to register a converter for only one way, we provide @ReadingConverter
and @WritingConverter
annotations to be used in the converter implementation.
由于不会从类路径或容器扫描中拾取转换器实例,因此必须显式注册转换器,以避免对转换服务进行不必要的注册以及由此注册产生的副作用。转换器使用 CustomConversions
注册,CustomConversions
是一个中心设施,允许基于源类型和目标类型注册和查询已注册的转换器。
Converters are subject to explicit registration as instances are not picked up from a classpath or container scan to avoid unwanted registration with a conversion service and the side effects resulting from such a registration. Converters are registered with CustomConversions
as the central facility that allows registration and querying for registered converters based on source- and target type.
CustomConversions
附带一组预定义的转换器注册:
CustomConversions
ships with a pre-defined set of converter registrations:
-
JSR-310 Converters for conversion between
java.time
,java.util.Date
andString
types.
本地时间类型的默认转换器(例如 |
Default converters for local temporal types (e.g. |
Converter Disambiguation
总体而言,我们检查 Converter
实现从哪些源类型和目标类型进行转换以及转换到哪些源类型和目标类型。根据其中一个是否是底层数据访问 API 本机可以处理的类型,我们将转换器实例注册为读转换器或写转换器。以下示例显示了写转换器和读转换器(请注意,Converter
上的限定词的顺序存在差异):
Generally, we inspect the Converter
implementations for the source and target types they convert from and to.
Depending on whether one of those is a type the underlying data access API can handle natively, we register the converter instance as a reading or a writing converter.
The following examples show a writing- and a read converter (note the difference is in the order of the qualifiers on Converter
):
// Write converter as only the target type is one that can be handled natively
class MyConverter implements Converter<Person, String> { … }
// Read converter as only the source type is one that can be handled natively
class MyConverter implements Converter<String, Person> { … }
Overriding Default Mapping with Custom Converters
要对映射过程进行更细粒度的控制,你可以向 CassandraConverter
实现(例如 MappingCassandraConverter
),注册 Spring Converters
。
To have more fine-grained control over the mapping process, you can register Spring Converters
with
CassandraConverter
implementations, such as MappingCassandraConverter
.
MappingCassandraConverter
首先检查是否任何 Spring Converters
都能处理特定类,然后才尝试映射对象本身。要“劫持”MappingCassandraConverter
的正常映射策略(可能是为了提高性能或其他自定义映射需要),你需要创建一个 Spring Converter
界面实现,并使用 MappingCassandraConverter
注册它。
MappingCassandraConverter
first checks to see whether any Spring Converters
can handle a specific class before attempting to map the object itself.
To "'hijack'" the normal mapping strategies of the MappingCassandraConverter
(perhaps for increased performance or other custom mapping needs), you need to create an implementation of the Spring Converter
interface and register it with the MappingCassandraConverter
.
Saving by Using a Registered Spring Converter
你可以将转换和保存合并到一个过程中,基本上使用转换器来进行保存操作。
You can combine converting and saving in a single process, basically using the converter to do the saving.
以下示例使用 Converter
将一个 Person
对象使用 Jackson 2 转换为 java.lang.String
:
The following example uses a Converter
to convert a Person
object to a java.lang.String
with Jackson 2:
/*
* 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;
import java.io.IOException;
import org.springframework.core.convert.converter.Converter;
import com.fasterxml.jackson.databind.ObjectMapper;
// tag::class[]
class PersonWriteConverter implements Converter<Person, String> {
public String convert(Person source) {
try {
return new ObjectMapper().writeValueAsString(source);
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
}
// end::class[]
Reading by Using a Spring Converter
类似于你可以合并保存和转换的方式,你还可以合并读取和转换。
Similar to how you can combine saving and converting, you can also combine reading and converting.
以下示例使用 Converter
,该 Converter
将 java.lang.String
转换为带有 Jackson 2 的 Person
对象:
The following example uses a Converter
that converts a java.lang.String
into a Person
object with Jackson 2:
/*
* 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;
import java.io.IOException;
import org.springframework.core.convert.converter.Converter;
import org.springframework.util.StringUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
// tag::class[]
class PersonReadConverter implements Converter<String, Person> {
public Person convert(String source) {
if (StringUtils.hasText(source)) {
try {
return new ObjectMapper().readValue(source, Person.class);
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
return null;
}
}
// end::class[]
Registering Spring Converters with CassandraConverter
Spring Data for Apache Cassandra Java 配置提供了一种方便的方法来注册 Spring Converter
实例:MappingCassandraConverter
。以下配置代码段显示了如何手动注册转换器以及配置 CustomConversions
:
Spring Data for Apache Cassandra Java configuration provides a convenient way to register Spring Converter
instances:
MappingCassandraConverter
.
The following configuration snippet shows how to manually register converters as well as configure CustomConversions
:
/*
* 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;
import java.util.ArrayList;
import java.util.List;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.cassandra.config.AbstractCassandraConfiguration;
import org.springframework.data.cassandra.core.convert.CassandraCustomConversions;
// tag::class[]
@Configuration
public class ConverterConfiguration extends AbstractCassandraConfiguration {
@Override
public CassandraCustomConversions customConversions() {
return CassandraCustomConversions.create(config -> {
config.registerConverter(new PersonReadConverter()));
config.registerConverter(new PersonWriteConverter()));
});
}
// other methods omitted...
// end::class[]
@Override
protected String getKeyspaceName() {
return null;
}
// tag::class[]
}
// end::class[]