Как сохранить Java 8 Instant в MongoDB как тип Date, используя Spring MongoTemplate?
У меня есть класс Java, имеющий Instant
тип переменной-члена:
public class SomeRecord {
private String someId;
private Instant someInstant;
// getters and setters
}
Я использую MongoTemplate для обновления someInstant
поле в базе данных:
public SomeRecord updateSomeRecordBySomeId(final String someId, Object someInstant) {
Query query = new Query();
query.addCriteria(Criteria.where("someId").is(someId));
Update update = new Update();
update.set("someInstant", someInstant);
return operations.findAndModify(query, update, new FindAndModifyOptions().returnNew(true), SomeRecord.class);
}
Это прекрасно работает, если я вызываю метод как:
updateSomeRecordBySomeId("SOME-ID", Instant.now());
сохраняя поле в БД как Date
тип: "someInstant" : ISODate("2017-07-11T07:26:44.269Z")
Теперь метод также может быть вызван как: updateSomeRecordBySomeId("SOME-ID", "2017-07-11T07:26:44.269Z");
В этом случае я получаю исключение как:
org.springframework.core.convert.ConverterNotFoundException: не найден конвертер, способный преобразовать тип [java.lang.String] в тип [java.time.Instant]
что имеет полный смысл. (Обновляет поле в БД как String
хоть. "someInstant" : "2017-07-11T07:26:44.269Z"
)
Поэтому я добавил конвертер следующим образом:
MongoConfig.java:
@Configuration
@ComponentScan(basePackages = {"dao package path here"})
public class MongoConfig {
@Autowired
private MongoDbFactory mongoDbFactory;
@Bean
public MongoTemplate mongoTemplate() {
MappingMongoConverter converter = new MappingMongoConverter(new DefaultDbRefResolver(mongoDbFactory),
new MongoMappingContext());
converter.setCustomConversions(new CustomConversions(Collections.singletonList(new StringToInstantConverter())));
return new MongoTemplate(mongoDbFactory, converter);
}
}
StringToInstantConverter.java:
public class StringToInstantConverter implements Converter<String, Instant> {
@Override
public Instant convert(String utcString) {
// TODO: Make it generic for any time-zone
return Instant.parse(utcString);
}
}
После добавления вышеуказанного конвертера я не получаю ConverterNotFoundException
больше, но поле someInstant
сохраняется как простая строка: "someInstant" : "2017-07-11T07:26:44.269Z"
И это то, что мой вопрос. Я знаю, что конвертер идентифицируется, поэтому я больше не получаю исключение. Но почему конвертер не конвертирует String
в Instant
? Почему поле сохраняется как простое String
? Неверно ли установлен преобразователь? Как написать конвертер для этого случая?
Замечания:
Я упростил код, чтобы сосредоточиться на актуальной проблеме. На самом деле метод не получает
someInstant
поле в качестве параметра. Поэтому написание перегруженного метода здесь неприменимо. Также любой видinstanceOf
проверка внутри метода не будет работать для реального сценария. Таким образом, акцент делается на вопрос, почему конверсия не происходит?Фактическим хранилищем данных для нас является DocumentDB, но мы используем DocumentDB с API MongoDB (поскольку Spring Data не поддерживает DocumentDB) для операций с нашей базой данных.
1 ответ
Ваша логика обновления написана независимым от типа способом: вы можете передать любой тип объекта (Integer, Long, Boolean, String, Date и т. Д.), И он будет сохранен в БД путем переопределения существующего значения / типа новым значением и новым типом, Примечание: ориентированные на документы базы данных, такие как MongoDB, не имеют фиксированной схемы, поэтому хранимые данные могут произвольно изменять типы данных.
Проблема, с которой вы столкнулись до того, как представили конвертер с ConverterNotFoundException
не во время действия обновления, а во время извлечения обновленного объекта и установки его в вашу модель Java-компонента: определен класс Java someInstant
свойство быть Instant
/ Date
тип, но база данных предоставлена String
значение.
После того, как вы представили конвертер, проблема чтения была решена, но только для String
а также Date
типы. Если вы обновите someInstant
собственность с некоторыми boolean
значение, вы вернетесь к проблеме, чтобы прочитать объект и сопоставить его с Java-бином.