Mongo 调用 mongo 存储库的保存方法时未调用日期自定义转换器
Mongo Date Custom Converter not being called when save method of mongo repository is invoked
我正在使用 linux Debian 9。我已经安装了 JDK 1.8。我使用的是 maven 版本 3.6,springboot 的版本是 2.1。 mongodb 版本是 3.6。
下面是 java 中 class 的模型,我试图将其保存在 mongodb:
@org.springframework.data.mongodb.core.mapping.Document(collection = FileContentIndexQueue.ENTITY_COLLECTION_NAME)
@CompoundIndexes({
@CompoundIndex(name = "state_timestamp", def = "{'state' : 1, 'timestamp': -1}")
})
@QuerySupertype
public class FileContentIndexQueue extends AbstractEntityNoLock {
...
private ZonedDateTime timestamp;
public FileContentIndexQueue() {
}
public FileContentIndexQueue(String fileId, String parentId, String childType, String indexName) {
super();
this.fileId = fileId;
this.parentId = parentId;
this.childType = childType;
this.indexName = indexName;
this.state = IndexingState.TODO;
this.timestamp = ZonedDateTime.now();
}
...
public ZonedDateTime getTimestamp() {
return timestamp;
}
public void setTimestamp(ZonedDateTime timestamp) {
this.timestamp = timestamp;
}
}
我正在使用 spring 数据 mongodb,下面是存储库 class 和自定义存储库 class 及其实现:
//Repository
public interface FileContentIndexQueueRepositoryMongoElastic extends
MongoElasticRepository<FileContentIndexQueue, String>
, FileContentIndexQueueRepositoryCustom
{
}
//Custom Repository
public interface FileContentIndexQueueRepositoryCustom {
void addFileWithContentToExtract(AbstractEntityNoLock entity, IFile file) throws CommonAllegatiException;
void removeFileWithContentToExtract(AbstractEntityNoLock entity, IFile file) throws CommonAllegatiException;
}
//Custom Repository Class Implementation
public class FileContentIndexQueueRepositoryCustomImpl implements FileContentIndexQueueRepositoryCustom {
@Autowired
@Lazy
private FileContentIndexQueueRepositoryMongoElastic fileContentIndexQueueRepositoryMongoElastic;
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
@Autowired
private MongoTemplate mongoTemplate;
@Override
public void addFileWithContentToExtract(AbstractEntityNoLock entity, IFile file) throws CommonAllegatiException {
if(entity.getId() == null) {
throw new CommonAllegatiException("Impossibile creare il FileContentIndexQueue da una entity senza id quindi non ancora salvata");
}
if(file == null) {
throw new CommonAllegatiException("Impossibile creare il FileContentIndexQueue da un IFile null");
}
if(file.getFileId() == null) {
throw new CommonAllegatiException("Impossibile creare il FileContentIndexQueue da un IFile senza id");
}
//da ricavare dalla entity
String parentId = entity.getId();
String indexName = elasticsearchTemplate.getPersistentEntityFor(entity.getClass()).getIndexName();
String fileId = file.getFileId();
FileContentIndexQueue fciq = new FileContentIndexQueue(fileId, parentId, CHILDTYPE, indexName);
fileContentIndexQueueRepositoryMongoElastic.save(fciq);
//**after the save is the point where the error is generated**
}
@Override
public void removeFileWithContentToExtract(AbstractEntityNoLock entity, IFile file) throws CommonAllegatiException {
...
}
}
上面的所有 classes 都是我用 Maven 从公司存储库下载的库的一部分,我无法修改。问题是 FileContentIndexQueue.java 模型有一个类型为 ZonedDateTime 的属性时间戳,mongo 数据库不支持这种类型并且 spring 数据没有内置转换器并抛出错误:org.bson.codecs.configuration.CodecConfigurationException: 找不到 class java.time.ZonedDateTime.
的编解码器
下面还有应用程序属性文件,其中包含我为 mongo 数据库和弹性搜索设置的属性:
#MongoDB
spring.data.mongodb.uri=mongodb://localhost:27017/?safe=true&w=1
spring.data.mongodb.database=operaTestDb
#Elasticsearch
spring.data.elasticsearch.cluster-name=elasticsearch
spring.data.elasticsearch.cluster-nodes=localhost:9300
spring.data.mongoelastic.save-on-elastic=true
我已尝试创建客户转换器并注册转换器以在调用 mongo 存储库的保存方法时调用。下面是我实现的解决方案代码。
@Configuration
public class ConverterConfig {
@Autowired
MongoDbFactory mongoDbFactory;
@Bean
public MongoTemplate mongoTemplate() throws UnknownHostException {
MappingMongoConverter converter = new MappingMongoConverter(
new DefaultDbRefResolver(mongoDbFactory), new MongoMappingContext());
converter.setCustomConversions(customConversions());
converter.afterPropertiesSet();
return new MongoTemplate(mongoDbFactory, converter);
}
@Bean
public MongoCustomConversions customConversions() {
List<Converter<?, ?>> converters = new ArrayList<>();
converters.add(DateToZonedDateTimeConverter.INSTANCE);
converters.add(ZonedDateTimeToDateConverter.INSTANCE);
return new MongoCustomConversions(converters);
}
enum DateToZonedDateTimeConverter implements Converter<Date, ZonedDateTime> {
INSTANCE;
@Override
public ZonedDateTime convert(Date source) {
return ZonedDateTime.ofInstant(source.toInstant(), ZoneId.systemDefault());
}
}
enum ZonedDateTimeToDateConverter implements Converter<ZonedDateTime, Date> {
INSTANCE;
@Override
public Date convert(ZonedDateTime source) {
return Date.from(source.toInstant());
}
}
}
即使在我创建转换器并注册它们时,问题仍然存在:org.bson.codecs.configuration.CodecConfigurationException:找不到 classjava.time.ZonedDateTime 的编解码器。 仍然存在。我在转换器中进行了调试,但它没有到达那里。就像转换器根本没有注册一样。我将不胜感激关于我应该如何调试的任何建议,或者如果您有不使用转换器的其他解决方案来解决此问题。将模型属性从 ZonedDatetime 修改为另一种日期格式不是选项,因为我无权访问该库。
亲切的问候,
兰多.
通过在 ConverterConfig class 中进行以下修改解决了此问题:
- 从方法 customConversions() 中删除 bean 注释
- 从转换方法中删除覆盖注释
- 在 DateToZonedDateTimeConverter 枚举中添加 @ReadingConverter 注解
- 在ZonedDateTimeToDateConverterenum中添加@WritingConverter注解
以下是适用于我的 ConverterConfig class 版本。我希望它能帮助你不要像我一样浪费时间。
@Configuration
public class ConverterConfig {
@Autowired
MongoDbFactory mongoDbFactory;
@Bean
public MongoTemplate mongoTemplate() throws UnknownHostException {
MappingMongoConverter converter = new MappingMongoConverter(new DefaultDbRefResolver(mongoDbFactory),
new MongoMappingContext());
converter.setCustomConversions(customConversions());
converter.afterPropertiesSet();
return new MongoTemplate(mongoDbFactory, converter);
}
public MongoCustomConversions customConversions() {
List<Converter<?, ?>> converters = new ArrayList<>();
converters.add(DateToZonedDateTimeConverter.INSTANCE);
converters.add(ZonedDateTimeToDateConverter.INSTANCE);
return new MongoCustomConversions(converters);
}
@ReadingConverter
enum DateToZonedDateTimeConverter implements Converter<Date, ZonedDateTime> {
INSTANCE;
public ZonedDateTime convert(Date source) {
return source == null ? null : ZonedDateTime.ofInstant(source.toInstant(), ZoneId.systemDefault());
}
}
@WritingConverter
enum ZonedDateTimeToDateConverter implements Converter<ZonedDateTime, LocalDateTime> {
INSTANCE;
public LocalDateTime convert(ZonedDateTime source) {
return source == null ? null : LocalDateTime.ofInstant(source.toInstant(), ZoneId.systemDefault());
}
}
}
我花了一个小时才弄清楚在最新版本的spring数据中mongo,应该使用org.bson.Document
而不是com.mongodb.BasicDBObject
。这是一个例子:
@Component
@WritingConverter
public class UserModelConverter implements Converter<UserModel, Document> {
@Override
public Document convert(UserModel s) {
Document obj = new Document();
obj.put("firstName", "FirstName");
obj.put("lastName", "LastName");
obj.remove("_class");
return obj;
}
}
我正在使用 linux Debian 9。我已经安装了 JDK 1.8。我使用的是 maven 版本 3.6,springboot 的版本是 2.1。 mongodb 版本是 3.6。
下面是 java 中 class 的模型,我试图将其保存在 mongodb:
@org.springframework.data.mongodb.core.mapping.Document(collection = FileContentIndexQueue.ENTITY_COLLECTION_NAME)
@CompoundIndexes({
@CompoundIndex(name = "state_timestamp", def = "{'state' : 1, 'timestamp': -1}")
})
@QuerySupertype
public class FileContentIndexQueue extends AbstractEntityNoLock {
...
private ZonedDateTime timestamp;
public FileContentIndexQueue() {
}
public FileContentIndexQueue(String fileId, String parentId, String childType, String indexName) {
super();
this.fileId = fileId;
this.parentId = parentId;
this.childType = childType;
this.indexName = indexName;
this.state = IndexingState.TODO;
this.timestamp = ZonedDateTime.now();
}
...
public ZonedDateTime getTimestamp() {
return timestamp;
}
public void setTimestamp(ZonedDateTime timestamp) {
this.timestamp = timestamp;
}
}
我正在使用 spring 数据 mongodb,下面是存储库 class 和自定义存储库 class 及其实现:
//Repository
public interface FileContentIndexQueueRepositoryMongoElastic extends
MongoElasticRepository<FileContentIndexQueue, String>
, FileContentIndexQueueRepositoryCustom
{
}
//Custom Repository
public interface FileContentIndexQueueRepositoryCustom {
void addFileWithContentToExtract(AbstractEntityNoLock entity, IFile file) throws CommonAllegatiException;
void removeFileWithContentToExtract(AbstractEntityNoLock entity, IFile file) throws CommonAllegatiException;
}
//Custom Repository Class Implementation
public class FileContentIndexQueueRepositoryCustomImpl implements FileContentIndexQueueRepositoryCustom {
@Autowired
@Lazy
private FileContentIndexQueueRepositoryMongoElastic fileContentIndexQueueRepositoryMongoElastic;
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
@Autowired
private MongoTemplate mongoTemplate;
@Override
public void addFileWithContentToExtract(AbstractEntityNoLock entity, IFile file) throws CommonAllegatiException {
if(entity.getId() == null) {
throw new CommonAllegatiException("Impossibile creare il FileContentIndexQueue da una entity senza id quindi non ancora salvata");
}
if(file == null) {
throw new CommonAllegatiException("Impossibile creare il FileContentIndexQueue da un IFile null");
}
if(file.getFileId() == null) {
throw new CommonAllegatiException("Impossibile creare il FileContentIndexQueue da un IFile senza id");
}
//da ricavare dalla entity
String parentId = entity.getId();
String indexName = elasticsearchTemplate.getPersistentEntityFor(entity.getClass()).getIndexName();
String fileId = file.getFileId();
FileContentIndexQueue fciq = new FileContentIndexQueue(fileId, parentId, CHILDTYPE, indexName);
fileContentIndexQueueRepositoryMongoElastic.save(fciq);
//**after the save is the point where the error is generated**
}
@Override
public void removeFileWithContentToExtract(AbstractEntityNoLock entity, IFile file) throws CommonAllegatiException {
...
}
}
上面的所有 classes 都是我用 Maven 从公司存储库下载的库的一部分,我无法修改。问题是 FileContentIndexQueue.java 模型有一个类型为 ZonedDateTime 的属性时间戳,mongo 数据库不支持这种类型并且 spring 数据没有内置转换器并抛出错误:org.bson.codecs.configuration.CodecConfigurationException: 找不到 class java.time.ZonedDateTime.
的编解码器下面还有应用程序属性文件,其中包含我为 mongo 数据库和弹性搜索设置的属性:
#MongoDB
spring.data.mongodb.uri=mongodb://localhost:27017/?safe=true&w=1
spring.data.mongodb.database=operaTestDb
#Elasticsearch
spring.data.elasticsearch.cluster-name=elasticsearch
spring.data.elasticsearch.cluster-nodes=localhost:9300
spring.data.mongoelastic.save-on-elastic=true
我已尝试创建客户转换器并注册转换器以在调用 mongo 存储库的保存方法时调用。下面是我实现的解决方案代码。
@Configuration
public class ConverterConfig {
@Autowired
MongoDbFactory mongoDbFactory;
@Bean
public MongoTemplate mongoTemplate() throws UnknownHostException {
MappingMongoConverter converter = new MappingMongoConverter(
new DefaultDbRefResolver(mongoDbFactory), new MongoMappingContext());
converter.setCustomConversions(customConversions());
converter.afterPropertiesSet();
return new MongoTemplate(mongoDbFactory, converter);
}
@Bean
public MongoCustomConversions customConversions() {
List<Converter<?, ?>> converters = new ArrayList<>();
converters.add(DateToZonedDateTimeConverter.INSTANCE);
converters.add(ZonedDateTimeToDateConverter.INSTANCE);
return new MongoCustomConversions(converters);
}
enum DateToZonedDateTimeConverter implements Converter<Date, ZonedDateTime> {
INSTANCE;
@Override
public ZonedDateTime convert(Date source) {
return ZonedDateTime.ofInstant(source.toInstant(), ZoneId.systemDefault());
}
}
enum ZonedDateTimeToDateConverter implements Converter<ZonedDateTime, Date> {
INSTANCE;
@Override
public Date convert(ZonedDateTime source) {
return Date.from(source.toInstant());
}
}
}
即使在我创建转换器并注册它们时,问题仍然存在:org.bson.codecs.configuration.CodecConfigurationException:找不到 classjava.time.ZonedDateTime 的编解码器。 仍然存在。我在转换器中进行了调试,但它没有到达那里。就像转换器根本没有注册一样。我将不胜感激关于我应该如何调试的任何建议,或者如果您有不使用转换器的其他解决方案来解决此问题。将模型属性从 ZonedDatetime 修改为另一种日期格式不是选项,因为我无权访问该库。
亲切的问候, 兰多.
通过在 ConverterConfig class 中进行以下修改解决了此问题:
- 从方法 customConversions() 中删除 bean 注释
- 从转换方法中删除覆盖注释
- 在 DateToZonedDateTimeConverter 枚举中添加 @ReadingConverter 注解
- 在ZonedDateTimeToDateConverterenum中添加@WritingConverter注解
以下是适用于我的 ConverterConfig class 版本。我希望它能帮助你不要像我一样浪费时间。
@Configuration
public class ConverterConfig {
@Autowired
MongoDbFactory mongoDbFactory;
@Bean
public MongoTemplate mongoTemplate() throws UnknownHostException {
MappingMongoConverter converter = new MappingMongoConverter(new DefaultDbRefResolver(mongoDbFactory),
new MongoMappingContext());
converter.setCustomConversions(customConversions());
converter.afterPropertiesSet();
return new MongoTemplate(mongoDbFactory, converter);
}
public MongoCustomConversions customConversions() {
List<Converter<?, ?>> converters = new ArrayList<>();
converters.add(DateToZonedDateTimeConverter.INSTANCE);
converters.add(ZonedDateTimeToDateConverter.INSTANCE);
return new MongoCustomConversions(converters);
}
@ReadingConverter
enum DateToZonedDateTimeConverter implements Converter<Date, ZonedDateTime> {
INSTANCE;
public ZonedDateTime convert(Date source) {
return source == null ? null : ZonedDateTime.ofInstant(source.toInstant(), ZoneId.systemDefault());
}
}
@WritingConverter
enum ZonedDateTimeToDateConverter implements Converter<ZonedDateTime, LocalDateTime> {
INSTANCE;
public LocalDateTime convert(ZonedDateTime source) {
return source == null ? null : LocalDateTime.ofInstant(source.toInstant(), ZoneId.systemDefault());
}
}
}
我花了一个小时才弄清楚在最新版本的spring数据中mongo,应该使用org.bson.Document
而不是com.mongodb.BasicDBObject
。这是一个例子:
@Component
@WritingConverter
public class UserModelConverter implements Converter<UserModel, Document> {
@Override
public Document convert(UserModel s) {
Document obj = new Document();
obj.put("firstName", "FirstName");
obj.put("lastName", "LastName");
obj.remove("_class");
return obj;
}
}