Mongo Date Custom Converter не вызывается при вызове метода сохранения из хранилища Монго - PullRequest
0 голосов
/ 24 октября 2019

Я работаю с Linux Debian 9. Я установил JDK 1.8. Я использую Maven версии 3.6, а версия Springboot - 2.1. Версия mongodb - 3.6.

Ниже приведена модель класса в Java, которую я пытаюсь сохранить в 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;
    }


}

Я использую данные весны 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 не поддерживает этот тип, а данные пружины не имеют встроенного преобразователя и выдают ошибку: 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:Не удается найти кодек для класса java.time.ZonedDateTime. все еще сохраняется. Я поставил отладчик в конвертерах, но он там не доходит. Это как конвертеры вообще не зарегистрированы. Буду признателен за любые предложения о том, что я должен сделать для отладки или если у вас есть другое решение этой проблемы без использования конвертеров. Изменение атрибута модели из ZonedDatetime в другой формат даты не допускается, поскольку у меня нет доступа к этой библиотеке.

С уважением, Рандо.

1 Ответ

0 голосов
/ 25 октября 2019

Эта проблема была решена путем внесения следующих изменений в класс ConverterConfig:

  1. удаление аннотации компонента из метода customConversions ()
  2. удаление аннотации переопределения из методов преобразования
  3. Добавление аннотации @ReadingConverter в перечисление DateToZonedDateTimeConverter
  4. Добавление аннотации @WritingConverter в ZonedDateTimeToDateConverterenum

Ниже приведена версия класса 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());
        }
    }
}
...