Pregunta ZonedDateTime con MongoDB


Tratando de usar ZonedDateTime con MongoDB. Soy capaz de ahorrar ZonedDateTime en MongoDB pero cuando miro el disco tiene tantas cosas innecesarias allí:

> "timestamp" : {
>             "dateTime" : ISODate("2016-12-13T13:45:53.991Z"),
>             "offset" : {
>                 "_id" : "-05:00",
>                 "totalSeconds" : -18000
>             },
>             "zone" : {
>                 "_class" : "java.time.ZoneRegion",
>                 "_id" : "America/New_York",
>                 "rules" : {
>                     "standardTransitions" : [ 
>                         NumberLong(-2717650800)
>                     ],
>                     "standardOffsets" : [ 
>                         {
>                             "_id" : "-04:56:02",
>                             "totalSeconds" : -17762
>                         }, 
>                         {
>                             "_id" : "-05:00",
>                             "totalSeconds" : -18000
>                         }
>                     ],
>                     "savingsInstantTransitions" : [ 
>                         NumberLong(-2717650800), 
>                         NumberLong(-1633280400), 
>                         NumberLong(-1615140000), 
>                         NumberLong(-1601830800), 
>                         NumberLong(-1583690400), 
>                         NumberLong(-1570381200),
> and so on....

Además, cuando intento recuperar esta misma fecha, me da los siguientes datos:

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

No tuve este problema cuando trabajo con LocalDateTime. La primera pregunta es si podemos cambiar algunas configuraciones en algún lugar que solo persistirán ISODate con ZonedDateTime? Segunda pregunta, ¿hay algo como Jsr310JpaConverters para mongodb?

ACTUALIZAR: Haciendo referencia al siguiente cuestionario, creé convertidores personalizados y los registré, sin embargo, el problema aún persiste. Spring Data MongoDB con Java 8 LocalDate MappingException

public class ZonedDateTimeToLocalDateTimeConverter implements Converter<ZonedDateTime, LocalDateTime> {
    @Override
    public LocalDateTime convert(ZonedDateTime source) {
        return source == null ? null : LocalDateTime.ofInstant(source.toInstant(), ZoneId
                .systemDefault());
    }
}

Y

public class LocalDateTimeToZonedDateTimeConverter implements Converter<LocalDateTime,
        ZonedDateTime> {
    @Override
    public ZonedDateTime convert(LocalDateTime source) {
        return source == null ? null : ZonedDateTime.of(source, ZoneId.systemDefault());
    }
}

Los registró de la siguiente manera:

@Bean
public CustomConversions customConversions(){
        List<Converter<?,?>> converters = new ArrayList<Converter<?,?>>();
        converters.add(new ZonedDateTimeToLocalDateTimeConverter());
        converters.add(new LocalDateTimeToZonedDateTimeConverter());
        return new CustomConversions(converters);
    }

@Bean
public MongoTemplate getMongoTemplate() throws UnknownHostException {
        MappingMongoConverter converter = new MappingMongoConverter(
                new DefaultDbRefResolver(getMongoDbFactory()), new MongoMappingContext());
        converter.setCustomConversions(customConversions());
        converter.afterPropertiesSet();
        return new MongoTemplate(getMongoDbFactory(), converter);
    }

5
2017-12-13 18:00


origen


Respuestas:


Parece que Spring tiene soporte para todo el convertidor de tiempo Java menos el convertidor de tiempo de fecha zonificada. Puede registrar uno de la siguiente manera.

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

@Bean
public MongoTemplate getMongoTemplate() throws UnknownHostException {
    MappingMongoConverter converter = new MappingMongoConverter(
            new DefaultDbRefResolver(getMongoDbFactory()), new MongoMappingContext());
    converter.setCustomConversions(customConversions());
    converter.afterPropertiesSet();
    return new MongoTemplate(getMongoDbFactory(), converter);
}

class DateToZonedDateTimeConverter implements Converter<Date, ZonedDateTime> {

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

class ZonedDateTimeToDateConverter implements Converter<ZonedDateTime, Date> {

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

Otra solución alternativa sería usar ZonedDateTime y cambiarlo hasta la fecha mientras se mantiene en MongoDB. Puede volver a cambiarlo fácilmente de la fecha a la hora de la fecha zonificada mientras se recupera.

A continuación se presentan los métodos relevantes para ayudar con las conversiones.

ZoneId zoneID = ZoneId.of("America/Chicago");

Desde ZonedDateTime a la fecha de Java util.

Instant instant = Instant.now();
ZonedDateTime zonedDateTime = instant.atZone(zoneId);
Date date = Date.from(zdt.toInstant());

Desde la fecha hasta ZonedDateTime

Instant instant = date.toInstant();
ZonedDateTime zonedDateTime = instant.atZone(zoneId);

La otra alternativa es implementar un códec personalizado para ayudar con las conversiones. He creado uno para YearMonth en Filtering YearMonth del documento de Mongo. Lo dejaré como ejercicio para el lector si desean crear un códec personalizado para la Hora de la Fecha de Zonificación.

Puede utilizar la siguiente biblioteca para el enfoque basado en codec.

https://github.com/ylemoigne/mongo-jackson-codec


10
2017-12-14 15:51



Después de pasar demasiado tiempo depurando esto, finalmente encontré una solución funcional para la última versión de Spring Boot / Spring Data. Esto actualmente me funciona en Spring Boot 2.0.0.M7.

Con la respuesta aceptada de Veeram, estaba recibiendo Couldn't find PersistentEntity for type 

Espero que esto ayude a alguien a evitar ir por el agujero del conejo.

@Configuration
public class MongoConfiguration {

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

    enum DateToZonedDateTimeConverter implements Converter<Date, ZonedDateTime> {

        INSTANCE;

        @Override
        public ZonedDateTime convert(Date source) {
            return ofInstant(source.toInstant(), systemDefault());
        }
    }

    enum ZonedDateTimeToDateConverter implements Converter<ZonedDateTime, Date> {

        INSTANCE;

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

3
2018-01-26 21:00