【Spring连载】使用Spring Data访问 MongoDB----对象映射之基于类型的转换器

【Spring连载】使用Spring Data访问 MongoDB----对象映射之基于类型的转换器

一、自定义转换

下面的Spring Converter实现示例将String对象转换为自定义Email值对象:

java 复制代码
@ReadingConverter
public class EmailReadConverter implements Converter<String, Email> {

  public Email convert(String source) {
    return Email.valueOf(source);
  }
}

如果你编写的转换器的源类型和目标类型都是native类型,框架无法确定是将其视为读取转换器还是写入转换器。将转换器实例同时注册为两者可能会导致不需要的结果。例如,Converter<String, Long>是不明确的,尽管在写入时尝试将所有String实例转换为Long实例可能没有意义。为了使你能够强制基础结构(infrastructure)仅以一种方式注册转换器,框架提供了在转换器实现中使用的@ReadingConverter和@WritingConverter注解。

转换器需要进行显式注册,因为实例不是从类路径或容器扫描中提取的,以避免向转换服务进行不必要的注册以及此类注册产生的副作用。转换器通过CustomConversions注册,CustomConversion是一个中心设施(facility),允许根据源和目标类型注册和查询已注册的转换器。

CustomConversions附带一组预定义的转换器注册:

  • JSR-310转换器,用于在java.time、java.util.Date和String类型之间转换。

本地时态类型的默认转换器(例如LocalDateTime到java.util.Date)依赖于系统默认时区设置在这些类型之间进行转换。你可以通过注册自己的转换器来覆盖默认转换器。

二、转换器消歧(Disambiguation)

通常,框架检查Converter实现,以确定它们转换的源和目标类型。根据其中一个类型是否是底层数据访问API可以natively处理的类型,框架将转换器实例注册为读转换器或写转换器。下面的例子展示了一个写转换器和一个读转换器(注意区别在于转换器上限定符的顺序):

java 复制代码
// 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> { ... }

三、基于类型的转换器

影响映射结果的最简单方法是通过@Field注解指定所需的native MongoDB目标类型。这允许在域模型中使用非MongoDB类型,如BigDecimal,同时将值持久化为原生org.bson.types.Decimal128格式。
例1:显式目标类型映射

java 复制代码
public class Payment {

  @Id String id;    --------1

  @Field(targetType = FieldType.DECIMAL128) --------2 
  BigDecimal value;

  Date date;        --------3

}
json 复制代码
{
  "_id"   : ObjectId("5ca4a34fa264a01503b36af8"), --------1
  "value" : NumberDecimal(2.099),                 --------2
  "date"   : ISODate("2019-04-03T12:11:01.870Z")  --------3
}

1. 表示有效ObjectId的字符串id值将自动转换。有关详细信息,请参见[映射层中如何处理_id字段](https://blog.csdn.net/gabriel_wang_sh/article/details/136385876#11__id_110)。
2. 所需的目标类型明确定义为Decimal128,它转换为NumberDecimal。否则,BigDecimal值将被转变为String。
3. 日期值由MongoDB driver本身处理,并存储为ISODate。

上面的代码段非常便于提供简单的类型提示。为了对映射过程获得更细粒度的控制,可以使用MongoConverter实现注册Spring转换器,例如MappingMongoConverter。

在尝试映射对象本身之前,MappingMongoConverter会检查是否有Spring转换器可以处理特定的类。为了"hijack"MappingMongoConverter的正常映射策略,可能是为了提高性能或其他自定义映射需求,你首先需要创建Spring Converter接口的实现,然后将其注册到MappingConverter。

有关Spring类型转换服务的更多信息,请参阅此处的参考文档

3.1 写转换

下面的例子展示了将Person对象转换为org.bson.Document的Converter的实现:

java 复制代码
public class PersonWriteConverter implements Converter<Person, Document> {

  public Document convert(Person source) {
    Document document = new Document();
    document.put("_id", source.getId());
    document.put("name", source.getFirstName());
    document.put("age", source.getAge());
    return document;
  }
}

3.2 读转换

下面的例子展示了一个转换器的实现,它将一个Document对象转换为一个Person对象:

java 复制代码
public class PersonReadConverter implements Converter<Document, Person> {

  public Person convert(Document source) {
    Person p = new Person((ObjectId) source.get("_id"), (String) source.get("name"));
    p.setAge((Integer) source.get("age"));
    return p;
  }
}

3.3 注册转换器

java 复制代码
class MyMongoConfiguration extends AbstractMongoClientConfiguration {

	@Override
	public String getDatabaseName() {
		return "database";
	}

	@Override
	protected void configureConverters(MongoConverterConfigurationAdapter adapter) {
		adapter.registerConverter(new com.example.PersonReadConverter());
		adapter.registerConverter(new com.example.PersonWriteConverter());
	}
}
相关推荐
亲爱的非洲野猪4 分钟前
Kafka消息积压的多维度解决方案:超越简单扩容的完整策略
java·分布式·中间件·kafka
wfsm7 分钟前
spring事件使用
java·后端·spring
微风粼粼24 分钟前
程序员在线接单
java·jvm·后端·python·eclipse·tomcat·dubbo
缘来是庄28 分钟前
设计模式之中介者模式
java·设计模式·中介者模式
rebel1 小时前
若依框架整合 CXF 实现 WebService 改造流程(后端)
java·后端
代码的余温2 小时前
5种高效解决Maven依赖冲突的方法
java·maven
慕y2742 小时前
Java学习第十六部分——JUnit框架
java·开发语言·学习
paishishaba2 小时前
Maven
java·maven
张人玉3 小时前
C# 常量与变量
java·算法·c#
Java技术小馆3 小时前
GitDiagram如何让你的GitHub项目可视化
java·后端·面试