【问题标题】:Mongo Date Custom Converter not being called when save method of mongo repository is invoked调用mongo存储库的保存方法时未调用Mongo Date Custom Converter
【发布时间】:2019-10-24 08:43:35
【问题描述】:

我正在使用 linux Debian 9。我已经安装了 JDK 1.8。我使用的是maven 3.6版本,springboot的版本是2.1。 mongodb版本是3.6。

下面是我试图保存在 mongodb 中的 java 中的类模型:

@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 data mongodb,下面是存储库类和自定义存储库类及其实现:

//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 {
              ...
    }   

}


以上所有类都是我用 maven 从公司存储库下载的库的一部分,我无法修改。问题是 FileContentIndexQueue.java 模型有一个属性时间戳,它是 ZonedDateTime 类型,mongo db 不支持这种类型,spring data 没有内置转换器并抛出错误:org.bson.codecs.configuration。 CodecConfigurationException:找不到类 java.time.ZonedDateTime 的编解码器。

下面还有应用程序属性文件,其中包含我为 mongo db 和弹性搜索设置的属性:

 #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: Can't find a codec for class java.time.ZonedDateTime.仍然存在。我在转换器中进行了调试,但没有到达那里。就像转换器根本没有注册一样。如果您有任何关于我应该如何调试的建议,或者您是否有其他解决方案而不使用转换器,我将不胜感激。将模型属性从 ZonedDatetime 修改为另一种日期格式不是选项,因为我无权访问该库。

亲切的问候, 兰多。

【问题讨论】:

    标签: mongodb spring-boot java-8 spring-data-mongodb


    【解决方案1】:

    通过在 ConverterConfig 类中进行以下修改解决了这个问题:

    1. 从方法 customConversions() 中删除 bean 注释
    2. 从转换方法中删除覆盖注释
    3. 在 DateToZonedDateTimeConverter 枚举中添加 @ReadingConverter 注解
    4. 在 ZonedDateTimeToDateConverterenum 中添加 @WritingConverter 注解

    以下是对我有用的 ConverterConfig 类版本。我希望它可以帮助你不要像我一样浪费时间。

    @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());
            }
        }
    }
    

    【讨论】:

    • 哇,这真的很有帮助,谢谢!
    • 很高兴我能帮上忙 :)
    【解决方案2】:

    我花了一个小时才弄明白在最新版的spring data 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;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-06-09
      • 1970-01-01
      • 2016-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多