如何使用 Spring MongoTemplate 将 Java 8 Instant 保存为 MongoDB 作为日期类型?

How to save Java 8 Instant to MongoDB as Date type using Spring MongoTemplate?

我有一个 Java class 具有 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: No converter found capable of converting from type [java.lang.String] to type [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?提供的转换器是否不正确?如何为这种情况编写转换器?

注:

您的更新逻辑是以类型不可知的方式编写的:您可以传递任何对象类型(Integer、Long、Boolean、String、Date 等),它将通过覆盖现有的 value/type 新值新类型。注意:像MongoDB这样的面向文档的数据库没有固定的模式,所以存储的数据可以任意改变数据类型。

在使用 ConverterNotFoundException 引入转换器之前,您遇到的问题不是在更新操作期间,而是在检索更新对象并将其设置到 Java bean 模型期间:Java class 将 someInstant 属性 定义为 Instant / Date 类型,但数据库提供了 String 值。

引入转换器后,读取问题已解决,但仅限于 StringDate 类型。如果您使用某些 boolean 值更新 someInstant 属性,您将回到问题以读取对象并将其映射到您的 Java bean。