如何完全自定义 Spring 数据 MongoDB 将类型信息写入文档的方式?
How to completely customize the way that type information gets written to a document by Spring Data MongoDB?
是否可以像在 Doctrine(PHP) 或 Jackson 库中那样对每个多态集合使用不同的类型属性(而不是 _class
)?当前的解决方案允许在文档字段中存储类型信息。默认情况下,它是一个完整的 class 名称,存储在名为 _class
.
的字段中
我们可以轻松更改它以保存一些自定义字符串(别名)而不是完整的 class 名称,并将默认鉴别器字段名称从 _class
更改为其他名称。
在我的情况下,我正在处理遗留数据库,而遗留应用程序仍在使用中。遗留应用程序使用 Doctrine (PHP) ODM 作为数据层。
Doctrine 允许通过注释定义鉴别器字段名称(SpringData 中的_class
),并且每个集合不同。
在 Spring 中,当我将 typeKey 传递给 DefaultMongoTypeMapper 时,它用于 所有集合 .
谢谢。
// MyCustomMongoTypeMapper.java
// ...
@SuppressWarnings("unchecked")
@Override
public <T> TypeInformation<? extends T> readType(DBObject source, TypeInformation<T> basicType) {
Assert.notNull(basicType);
Class<?> documentsTargetType = null;
Class<? super T> parent = basicType.getType();
while (parent != null && parent != java.lang.Object.class) {
final String discriminatorKey = getDiscriminatorKey(parent); //fetch key from annotation
if (null == discriminatorKey) {
parent = parent.getSuperclass();
} else {
accessor.setKey(discriminatorKey);
return super.readType(source, basicType);
}
}
accessor.resetKey();
return super.readType(source, basicType);
}
应该为您工作的是完全交换 MappingMongoConverter
使用的 MongoTypeMapper
实例。正如您所发现的,已经可用的实现采用了一个通用字段名称,并采用了另一种策略来编写完全限定的 class 名称或别名等。
但是,您应该能够自己编写并特别关注以下方法:
void writeType(TypeInformation<?> type, DBObject dbObject)
— 您基本上获得了类型并完全控制将其放入 DBObject 的位置和方式。
<T> TypeInformation<? extends T> readType(DBObject source, TypeInformation<T> defaultType);
——你得到了在阅读端声明的类型(即通常是层次结构中最常见的类型),并基于它必须从给定的源文档中查找类型。我想这恰恰与另一种方法中要实现的相反。
最后一点,我强烈建议不要对不同的集合使用不同的类型字段名称,因为在阅读方面,您可能 运行 到 Object
声明的地方 属性 而且您基本上不知道在文档中的何处寻找。
是否可以像在 Doctrine(PHP) 或 Jackson 库中那样对每个多态集合使用不同的类型属性(而不是 _class
)?当前的解决方案允许在文档字段中存储类型信息。默认情况下,它是一个完整的 class 名称,存储在名为 _class
.
我们可以轻松更改它以保存一些自定义字符串(别名)而不是完整的 class 名称,并将默认鉴别器字段名称从 _class
更改为其他名称。
在我的情况下,我正在处理遗留数据库,而遗留应用程序仍在使用中。遗留应用程序使用 Doctrine (PHP) ODM 作为数据层。
Doctrine 允许通过注释定义鉴别器字段名称(SpringData 中的_class
),并且每个集合不同。
在 Spring 中,当我将 typeKey 传递给 DefaultMongoTypeMapper 时,它用于 所有集合 .
谢谢。
// MyCustomMongoTypeMapper.java
// ...
@SuppressWarnings("unchecked")
@Override
public <T> TypeInformation<? extends T> readType(DBObject source, TypeInformation<T> basicType) {
Assert.notNull(basicType);
Class<?> documentsTargetType = null;
Class<? super T> parent = basicType.getType();
while (parent != null && parent != java.lang.Object.class) {
final String discriminatorKey = getDiscriminatorKey(parent); //fetch key from annotation
if (null == discriminatorKey) {
parent = parent.getSuperclass();
} else {
accessor.setKey(discriminatorKey);
return super.readType(source, basicType);
}
}
accessor.resetKey();
return super.readType(source, basicType);
}
应该为您工作的是完全交换 MappingMongoConverter
使用的 MongoTypeMapper
实例。正如您所发现的,已经可用的实现采用了一个通用字段名称,并采用了另一种策略来编写完全限定的 class 名称或别名等。
但是,您应该能够自己编写并特别关注以下方法:
void writeType(TypeInformation<?> type, DBObject dbObject)
— 您基本上获得了类型并完全控制将其放入 DBObject 的位置和方式。<T> TypeInformation<? extends T> readType(DBObject source, TypeInformation<T> defaultType);
——你得到了在阅读端声明的类型(即通常是层次结构中最常见的类型),并基于它必须从给定的源文档中查找类型。我想这恰恰与另一种方法中要实现的相反。
最后一点,我强烈建议不要对不同的集合使用不同的类型字段名称,因为在阅读方面,您可能 运行 到 Object
声明的地方 属性 而且您基本上不知道在文档中的何处寻找。