简体   繁体   中英

Mongo auditable ZonedDateTime fields don't work in Spring Boot 2

In a Spring Boot project, I use annotations like @CreatedDate to save information about dates when the corresponding documents are created / updated. ZonedDateTime is used throughout the project, so the annotated fields are ZonedDateTime, too. To enable conversion between the Mongo's date format and ZonedDateTime, custom converters are used.

Now, when using Spring Boot 1.5.x, the custom converters work perfectly for the auditable fields. In Spring Boot 2.0.x, the custom converters work for all fields, but not for the auditable ones. Thus, if I remove @EnableMongoAuditing, everything works fine (all ZonedDateTime fields throughout the project are persisted to and read from Mongo correctly), but the created / updated date fields are empty. If I enable mongo auditing, I get the following exception when trying to save a document:

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]

My Mongo config:

@Configuration
@EnableMongoAuditing
public class MongoConfig {
    @Bean
    public MongoCustomConversions customConversions(){
        List<Converter<?,?>> converters = new ArrayList<>();
        converters.add(new ZonedDateTimeToDateConverter());
        converters.add(new DateToZonedDateTimeConverter());
        return new MongoCustomConversions(converters);
    }
}

This is how the corresponding fields look like:

abstract class BaseModel {

    @Id
    private String id;
    @CreatedDate
    private ZonedDateTime created;
    @LastModifiedDate
    private ZonedDateTime updated;
}

Is there a way to make the converters work for mongo auditable fields, other than downgrading to Spring Boot 1.5.x?

TL;DR:

Besides register a MongoCustomConversions bean. Create a bean of DateTimeProvider , and register it into your @EnableXXXAuditing(dateTimeProviderRef = "dateTimeProvider")

public class CustomDateTimeProvider implements DateTimeProvider {

    @Override
    public Optional<TemporalAccessor> getNow() {
        return Optional.of(ZonedDateTime.now());
    }
}
@Configuration
@EnableMongoAuditing(dateTimeProviderRef = "dateTimeProvider") // beanName
public class MongoConfig {
    @Bean
    public MongoCustomConversions customConversions(){
        List<Converter<?,?>> converters = new ArrayList<>();
        converters.add(new ZonedDateTimeToDateConverter());
        converters.add(new DateToZonedDateTimeConverter());
        return new MongoCustomConversions(converters);
    }

    // The DateTimeProvider bean with beanName="dateTimeProvider" is registered here
    @Bean
    public DateTimeProvider dateTimeProvider() {
        return new CustomDateTimeProvider();
    }
}

FYI :

When you use @EnableXXXAuditing , Spring will register a AuditHandler that is responsible for adding auditing data to your model. It has 2 main components: DateTimeProvider and AuditorAware<?> . You could register these 2 components in AuditHandler by declaring them in @EnableXXXAuditing . For example:

@EnableXXXAuditing(
    auditorAwareRef = "auditorAware", // beanName
    dateTimeProviderRef = "dateTimeProvider" // beanName
)
  • DateTimeProvider in short, is responsible for @CreatedDate and @LastModifiedDate
  • AuditorAware in short, is responsible for @CreatedBy and @LastModifiedBy

The default implementation of DateTimeProvider is CurrentDateTimeProvider that returns a instance of LocalDateTime . That's why you got the error with your ZonedDateTime CreatedDate, LastModifiedDate.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM