Reputation: 1512
I am working with linux Debian 9. I have installed JDK 1.8. I am using maven version 3.6 and the version of springboot is 2.1. The mongodb version is 3.6.
Below is the model of class in java which i am trying to save in 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;
}
}
I am using spring data mongodb and below is the repository class and the custom repository class with its implementations:
//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 {
...
}
}
All the classes above are part of library which i have downloaded with maven from the corporate repository and i cannot modify. The problem is that the FileContentIndexQueue.java model has an attribute timestamp which is type ZonedDateTime and mongo db does not support this type and spring data does not have built in converter and throws the error: org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class java.time.ZonedDateTime.
Also below it is the application properties file with properties that i have set for mongo db and elastic search:
#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
I have tried to created customer converters and register the converter to be called when a save method of mongo repository is invoked. Below it is the code of solution that i have implemented.
@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());
}
}
}
The problem is even when i create the converters and register them , the error : org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class java.time.ZonedDateTime. still persists. I put a debug in converters but it doesn't reach there. It is like the converters are not registered at all. I would appreciate any suggestion on what should i do to debug or if you have another solution for this problem without using converters. Modifying the model attribute from ZonedDatetime to another date format is not option since i don't have access to that library.
Kind Regards, Rando.
Upvotes: 5
Views: 7829
Reputation: 2889
It took me one hour to figure out in the latest version of spring data mongo, org.bson.Document
should be used instead of com.mongodb.BasicDBObject
. Here is an example:
@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;
}
}
Upvotes: 2
Reputation: 1512
This problem was solved by doing the following modification in ConverterConfig class:
Below is the version of ConverterConfig class that worked for me. I hope it helps you not to lose time like I did.
@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());
}
}
}
Upvotes: 4