Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Register a new Date Converter Auditable in Spring Data MongoDB for ZonedDateTime

I want my auditable (@CreatedDate and @LastModifiedDate) MongoDB document to work with ZonedDateTime fields.

Apparently this type is not supported by Spring Data (have a look at org.springframework.data.auditing.AnnotationAuditingMetadata).

Framework version: Spring Boot 2.0.0 and Spring Data MongoDB 2.0.0

Spring Data auditing error:

java.lang.IllegalArgumentException: Invalid date type for member <MEMBER NAME>!
Supported types are [org.joda.time.DateTime, org.joda.time.LocalDateTime, java.util.Date, java.lang.Long, long].

Mongo configuration:

@Configuration
@EnableMongoAuditing
public class MongoConfiguration {

}

The auditable entity:

public abstract class BaseDocument {

    @CreatedDate
    private ZonedDateTime createdDate;

    @LastModifiedDate
    private ZonedDateTime lastModifiedDate;

}

Things I tried

I also tried creating a custom converter for ZonedDateTime, but it is not considered by Spring Data. The class DateConvertingAuditableBeanWrapper has a ConversionService which is configured in the constructor method with JodaTimeConverters, Jsr310Converters and ThreeTenBackPortConverters.

Custom converter:

@Component
public class LocalDateTimeToZonedDateTimeConverter implements Converter<LocalDateTime, ZonedDateTime> {

    @Override
    public ZonedDateTime convert(LocalDateTime source) {
        return source.atZone(ZoneId.systemDefault());
    }

}

Spring Data DateConvertingAuditableBeanWrapper:

class DefaultAuditableBeanWrapperFactory implements AuditableBeanWrapperFactory {

    abstract static class DateConvertingAuditableBeanWrapper implements AuditableBeanWrapper {

        private final ConversionService conversionService;

    }
}

Is it possible to audit ZonedDateTime fields?

How can I register a converter?

like image 529
ciri-cuervo Avatar asked Apr 05 '17 16:04

ciri-cuervo


1 Answers

Create a DateTimeProvider to provide the current time to be used when auditing:

@Component("dateTimeProvider")
public class CustomDateTimeProvider implements DateTimeProvider {
    
    @Override
    public Optional<TemporalAccessor> getNow() {
        return Optional.of(ZonedDateTime.now());
    }
}

And then:

  • Reference the DateTimeProvider component in the @EnableMongoAuditing annotation;
  • Create Converters for Date and ZonedDateTime;
  • Add the Converter instances to a MongoCustomConversions instance;
  • Expose the MongoCustomConversions instance as a @Bean.
@Configuration
@EnableMongoAuditing(dateTimeProviderRef = "dateTimeProvider")
public class MongoConfiguration {
    
    @Bean
    public MongoCustomConversions customConversions() {
        List<Converter<?, ?>> converters = new ArrayList<>();
        converters.add(new DateToZonedDateTimeConverter());
        converters.add(new ZonedDateTimeToDateConverter());
        return new MongoCustomConversions(converters);
    }

    class DateToZonedDateTimeConverter implements Converter<Date, ZonedDateTime> {

        @Override
        public ZonedDateTime convert(Date source) {
            return source == null ? null : 
                    ZonedDateTime.ofInstant(source.toInstant(), ZoneId.systemDefault());
        }
    }

    class ZonedDateTimeToDateConverter implements Converter<ZonedDateTime, Date> {

        @Override
        public Date convert(ZonedDateTime source) {
            return source == null ? null : Date.from(source.toInstant());
        }
    }
}

I wouldn't, however, use ZonedDateTime for this purpose. I would stick to OffsetDateTime:

OffsetDateTime, ZonedDateTime and Instant all store an instant on the time-line to nanosecond precision. Instant is the simplest, simply representing the instant. OffsetDateTime adds to the instant the offset from UTC/Greenwich, which allows the local date-time to be obtained. ZonedDateTime adds full time-zone rules.

It is intended that ZonedDateTime or Instant is used to model data in simpler applications. This class may be used when modeling date-time concepts in more detail, or when communicating to a database or in a network protocol.

like image 117
cassiomolin Avatar answered Nov 15 '22 11:11

cassiomolin