13

I have simple document with Java 8 date/time fields

@Document
public class Token {
    private Instant createdAt;
    ...
}

that I want to persist with Spring Data MongoDB version 1.5. But fields of type java.time.Instant could not be de-serialized correctly because MappingMongoConverter lacks converters for java.time classes.

In Spring 4 I found org.springframework.format.datetime.standard.DateTimeConverters with different Converters including InstantToLongConverter and LongToInstantConverter declared as private static classes.

How can I configure MongoTemplate to use them to map Instant fields to longs?

JodaStephen
  • 60,927
  • 15
  • 95
  • 117
Sokolof
  • 2,271
  • 2
  • 19
  • 30

2 Answers2

15

I don't know if this is the best way but I added Java 8 Date/Time (JSR-310) types support to Spring Data MongoDB 1.5.0.RELEASE like this:

  1. First step. Add simple Spring Converters

    public class InstantToLongConverter implements Converter<Instant, Long> {
        @Override
        public Long convert(Instant instant) {
            return instant.toEpochMilli();
        }
    }
    
    public class LongToInstantConverter implements Converter<Long, Instant> {
        @Override
        public Instant convert(Long source) {
            return Instant.ofEpochMilli(source);
        }
    }
    
    public class LocalDateToStringConverter implements Converter<LocalDate, String> {
        @Override
        public String convert(LocalDate localDate) {
            return localDate.toString();
        }
    }
    
    public class StringToLocalDateConverter implements Converter<String, LocalDate> {
        @Override
        public LocalDate convert(String source) {
            return LocalDate.parse(source);
        }
    }
    
  2. Second step. Register these custom Converters with MappingMongoConverter in your AbstractMongoConfiguration implementation like this:

    @Configuration
    @EnableMongoRepositories(basePackages = {"my.app.repository"})
    public class MongoConfiguration extends AbstractMongoConfiguration {
    
        ...
    
        @Override
        public CustomConversions customConversions() {
            return new CustomConversions(Arrays.asList(
                    new InstantToLongConverter(), new LongToInstantConverter(),
                    new LocalDateToStringConverter(), new StringToLocalDateConverter()));
        }
    }
    

Now your document's Instant fields will be persisted as long values and LocalDates as Strings.

Sokolof
  • 2,271
  • 2
  • 19
  • 30
  • I am still getting org.springframework.data.mapping.model.MappingException: No property null found on entity class java.time.Instant to bind constructor parameter to! Can you please check the github project I have updated with the converter's you mentioned. – Vineet Bhatia Jun 02 '14 at 00:56
  • Try adding @ComponentScan(basePackages = "stackoverflow.java8mongo") annotation to Application class – Sokolof Jun 02 '14 at 19:56
  • 2
    But this coverters are already provided by spring since spring version 4.0.1. See `org.springframework.format.datetime.standard.DateTimeConverters` – Zarathustra Jul 25 '14 at 15:27
  • These converters are mentioned in the question. But as of `spring-data-mongodb-1.6.1.RELEASE` they are still not registered for Mongo type mapping. – Sokolof Dec 14 '14 at 05:15
  • By the way. If you want to use this converters check first this answer to save you work http://stackoverflow.com/questions/32507470/unable-to-find-org-springframework-format-datetime-standard-datetimeconverters/32510002#32510002 – borjab Sep 11 '15 at 08:09
3

@user882209 explained it all just perfectly.
Since Spring Data MongoDB 1.7 the support for JSR-310 has been added.
If application is backed by Spring Boot every version over 1.2.8 would contain it as well.
In a Spring Boot-ed app you can just do it the following:

@Configuration
public class MongoDbConfig {

    @Autowired
    private MongoDbFactory mongoDbFactory;

    @Bean
    public MongoTemplate mongoTemplate() {
        MappingMongoConverter converter = new MappingMongoConverter(new DefaultDbRefResolver(mongoDbFactory),
            new MongoMappingContext());
        converter.setCustomConversions(new CustomConversions(Arrays.asList(...)));

    return new MongoTemplate(mongoDbFactory, converter);
    }
}

The following converters are provided by the Jsr310Converters class:
DateToLocalDateTimeConverter - LocalDateTimeToDateConverter DateToLocalDateConverter - LocalDateToDateConverter DateToLocalTimeConverter - LocalTimeToDateConverter DateToInstantConverter - InstantToDateConverter

magiccrafter
  • 5,175
  • 1
  • 56
  • 50
  • 1
    If you extend your config from `AbstractMongoConfiguration` you can even spare the `mongoTemplate` bean and all available converters are registered. – ChrLipp Mar 04 '16 at 15:49