【问题标题】:Spring Mongodb - Cannot write custom Converter for java.time.PeriodSpring Mongodb - 无法为 java.time.Period 编写自定义转换器
【发布时间】:2016-08-19 15:06:50
【问题描述】:

我将 Spring Cloud Brixton.SR4 与 Spring Data MongoDB 一起使用。

我有一个非常简单的实体:

@Document
public class Foo{
    private Period period;

    //getter & setter
}

因为jsr310 不支持java.time.Period,所以我正在创建自定义转换器:

class Converters {
    @Component
    @WritingConverter
    static class PeriodToStringConverter implements Converter<Period, String> {
        @Override
        public String convert(Period period) {
            return period.toString();
        }
    }

    @ReadingConverter
    @Component
    static class StringToPeriodConverter implements Converter<String, Period> {

        @Override
        public Period convert(String s) {
            return Period.parse(s);
        }
    }

现在我在我的配置类中注册它们,扩展 AbstractMongoConfiguration:

    @Bean
    @Override
    public MappingMongoConverter mappingMongoConverter() throws Exception {
        DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory());
        MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, mongoMappingContext());
        final CustomConversions conversions = customConversions();
        log.info("hasCustomWriteTarget(Period.class): " + conversions.hasCustomWriteTarget(Period.class));
        log.info("hasCustomWriteTarget(Period.class, String.class): " + conversions.hasCustomWriteTarget(Period.class, String.class));
        log.info("hasCustomReadTarget(String.class, Period.class): " + conversions.hasCustomReadTarget(String.class, Period.class));
        converter.setCustomConversions(conversions);
        converter.afterPropertiesSet(); //probably not needed, trying out of despair
        return converter;
    }

    @Bean
    @Override
    public CustomConversions customConversions() {
        List<Converter> converters = new ArrayList<>();
        converters.add(new Converters.PeriodToStringConverter());
        converters.add(new Converters.StringToPeriodConverter());
        return new CustomConversions(converters);
    }

当我启动我的应用程序时,我会在日志中看到:

hasCustomWriteTarget(Period.class): true
hasCustomWriteTarget(Period.class, String.class): true
hasCustomReadTarget(String.class, Period.class): true

现在我创建一个新的Foo 并将其保存到我的存储库中:

Foo foo = new Foo();
foo.setPeriod(Period.of(2, 0, 1));
fooRepository.save(foo);

现在奇怪的事情发生了:

在 Mongodb 中我看到了:

{
  "_id": ObjectId("xxxx"),
  "period": {
      "years" : 0,
      "months" : 2,
      "days" : 1
    }
}

所以这已经是错误的了。应该保存为String

当我尝试在 Java 中读取对象时,我得到:

org.springframework.data.mapping.model.MappingException: No property null found on entity class java.time.Period to bind constructor parameter to!

我调试了MappingMongoConverter中的代码:

    if (conversions.hasCustomReadTarget(dbo.getClass(), rawType)) {
        return conversionService.convert(dbo, rawType);
    }

因为我的对象没有存储为字符串,所以dbo 变量实际上是BasicDbObject,因此我没有用于此的转换器。

知道为什么我的写转换器没有被用来持久化Period吗?

我的类路径中有jackson-datatype-jdk8,这可能是问题吗? jackson 是否会因为坚持使用 Mongodb 而参与其中?

编辑

这似乎是一个注册问题。当我调试代码时,MappingMongoConverter 中使用的CustomConversion 对象与我创建的对象不同。而且它没有我创建的自定义转换器

【问题讨论】:

    标签: java spring spring-data spring-data-mongodb


    【解决方案1】:

    好吧,这太愚蠢了......

    我也在创建自己的MongoTemplate

    @Bean
    public MongoTemplate mongoTemplate() throws Exception {
        return new MongoTemplate(mongoDbFactory());
    }
    

    这基本上忽略了我的自定义转换器。修复它:

    @Bean
    public MongoTemplate mongoTemplate() throws Exception {
        return new MongoTemplate(mongoDbFactory(), mappingMongoConverter());
    }
    

    【讨论】:

    • 这对我有帮助,但是为什么要创建我们自己的MongoTemplate?您的方法与默认(超类)实现相同。
    • 这是因为在我的情况下,我使用的是自定义 MongoDBFactory。我想如果你不这样做,你可以按照你的建议使用默认实现
    • 为了给你完整的故事是因为我必须在这个方法中做一些像mongodbFactory.setMongoTemplate(mongoTemplate); 这样的事情。否则你是对的,它有点没用
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-06
    • 1970-01-01
    • 2010-10-21
    • 2021-03-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多