强制Spring Data MongoDB将所有日期读作Joda DateTime类型

时间:2015-04-03 20:41:19

标签: java spring mongodb datetime

我试图坚持以下文件:

class Document {
    ...
    private Map data;
    ...
}

要存储日期,我使用的是Joda的DateTime对象:

data.put("date", DateTime.now());

我正在使用MongoRepository来保存数据。写得很好,我可以看到mongoDB有一个日期类型。

但是,当我读取数据时,我的地图不包含DateTime,而是Date对象。

我明白了,没有什么可以告诉Spring将正在读取的对象的类型从Date(默认)更改为DateTime,因为我没有阅读具体类型。

有没有办法让MongoTemplate / MongoRepository在读取时始终将java.util.Date转换为Joda DateTime?

这可能与转换器有关,但我无法找到如何执行此操作的示例。

感谢。 -AP _

2 个答案:

答案 0 :(得分:2)

所以,最后我不得不做出一点妥协。由于我使用Map来保存任意数据,因此无法调用转换器,因为任何东西都可以设置为Object,因此Spring Data不需要进行从Date到DateTime的任何转换。 / p>

我没有使用通用Map,而是创建了我自己的类型,它只是从Map扩展而来:

public class EventData extends HashMap<String, Object> {
    ...
}

然后,我将我的父类更改为使用EventData而不是Map:

public class Event implements Serializable {
    private final EventData
        data;

    ...
}

现在,有了EventData,我可以创建一个自定义映射器:

@ReadingConverter
public class ConsumerHandlerEventDataReadConverter implements Converter<DBObject, EventData> {

    @Resource
    private MappingMongoConverter
        mappingMongoConverter;

    @Override
    public EventData convert(final DBObject source) {
        //First, use the general mapping mongo converter to read the source as it would normally be read
        //
        final EventData
            eventData =
                mappingMongoConverter
                    .read(
                        EventData.class,
                        source
                    );

        //Now replaces all occurances of Date in EventData with DateTime
        //
        for (final Map.Entry<String, Object> entry : eventData.entrySet()) {
            //Get the value of this entry
            //
            final Object
                entryValue =
                    entry
                        .getValue();

            //If it's a date, replace with Datetime
            //
            if (entryValue instanceof Date) {
                entry
                    .setValue(
                        new DateTime(
                            entryValue
                        )
                    );
            }
        }

        //Return result
        //
        return
            eventData;
    }
}

大多数映射都是由标准映射器完成的,所以我只是连接了一个“不同的”MappingMongoConverter并使用它的read方法来读取数据。然后,我查找所有Date对象并用DateTime替换它们。

要将我的转换器添加到Mongo,我使用MappingMongoConverter注册自定义转换类型:

@Configuration
public class ConsumerHandlerMongoDBConfiguration {
    ...
    @Bean
    public CustomConversions customConversions() {
        return
            new CustomConversions(
                Arrays.asList(
                    consumerHandlerEventDataReadConverter()
                )
            );
    }

    @Bean
    @Description("Mapping mongo converter for the event")
    public MappingMongoConverter consumerProcessHandlerMappingMongoConverter() {
        final MappingMongoConverter
            converter =
                new MappingMongoConverter(
                    mongoDBConfiguration.dbRefResolver(),
                    mongoDBConfiguration.mongoMappingContext()
                );

        converter
            .setTypeMapper(
                mongoDBConfiguration.mongoTypeMapper()
            );

        converter
            .setCustomConversions(
                customConversions()
            );

        return
            converter;
    }
    ...
}

理想情况下,我希望以某种方式创建一个映射器,MappingMongoConverter在处理Date类型时不会特别在EventData的上下文中总是可以参考,但是,查看Spring Data中的readMap(...)代码,我看到了这不会发生:

private Object getPotentiallyConvertedSimpleRead(Object value, Class<?> target) {

    if (value == null || target == null || target.isAssignableFrom(value.getClass())) {
        return value;
    }

    if (conversions.hasCustomReadTarget(value.getClass(), target)) {
        return conversionService.convert(value, target);
    }

    if (Enum.class.isAssignableFrom(target)) {
        return Enum.valueOf((Class<Enum>) target, value.toString());
    }

    return conversionService.convert(value, target);
}

如果target.isAssignableFrom(value.getClass()),上面的代码将不会调用任何映射器,并且因为所有内容都可以分配给Object,所以无论如何都无法注册自定义映射器。代码中的下一个语句确实检查了是否转换了.hasCustomReadTarget,但我们从来没有达到它。

无论如何,对于那些试图与转换器做类似事情的人来说,下次也要记录下来。

-AP _

答案 1 :(得分:0)

您必须实现自己的转换器,然后在启用MongoDB存储库(customConversions())的类中覆盖@EnableMongoRepositories

它还取决于您使用的 Spring Data 版本;到目前为止,我记得还有DateTimeConverters

类似于this,但实现了Spring的Converter<T, K>界面。