4

我有一个具有Instant成员变量类型的 Java 类:

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"

这就是我的问题。我知道转换器正在被识别,这就是我不再遇到异常的原因。但为什么转换器不转换StringInstant?为什么该领域被坚持为平原String?提供的转换器是否不正确?如何为这种情况编写转换器?

笔记:

  • 我已经简化了代码以专注于实际问题。实际上,该方法不接收该someInstant字段作为参数。所以在这里编写重载方法将不适用。instanceOf此外,该方法内的任何类型的检查都不适用于实际情况。所以重点是为什么没有发生转换的问题?

  • 对我们来说实际的数据存储是 DocumentDB,但是我们使用DocumentDB 和 MongoDB API(因为 Spring Data 不支持 DocumentDB)来进行数据库操作。

4

1 回答 1

2

您的更新逻辑以与类型无关的方式编写:您可以传递任何对象类型(整数、长整数、布尔值、字符串、日期等),并将通过用新值新类型覆盖现有值/类型将其保留在数据库中. 注意:像 MongoDB 这样的面向文档的数据库没有固定的模式,因此存储的数据可以任意更改数据类型。

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

在您介绍了转换器后,阅读问题得到了解决,但仅限于StringDate类型。如果您someInstant使用某个值更新属性boolean,您将回到问题上来读取对象并将其映射到您的 Java bean。

于 2017-07-11T22:07:57.267 回答