All Downloads are FREE. Search and download functionalities are using the official Maven repository.

no.nav.common.json.DateModule Maven / Gradle / Ivy

The newest version!
package no.nav.common.json;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.deser.std.StdScalarDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.StdScalarSerializer;

import java.io.IOException;
import java.time.*;
import java.time.format.DateTimeParseException;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.regex.Pattern;

import static java.time.LocalTime.NOON;
import static java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME;
import static no.nav.common.utils.StringUtils.of;

public class DateModule {

    public static final ZoneId DEFAULT_ZONE = ZoneId.of("Europe/Paris");
    private static final List providers = List.of(
            new LocalDateProvider(),
            new LocalDateTimeProvider(),
            new ZonedDateTimeProvider(),
            new DateProvider()
    );

    public static Module module() {
        SimpleModule module = new SimpleModule();
        providers.forEach((v) -> {
            module.addSerializer(v.serializer);
            module.addDeserializer(v.targetClass, v.deSerializer);
        });
        return module;
    }

    private abstract static class BaseProvider {

        private final Class targetClass;
        private final JsonSerializer serializer;
        private final JsonDeserializer deSerializer;

        protected abstract T toValue(ZonedDateTime zonedDateTime);

        protected abstract ZonedDateTime from(T value);

        public BaseProvider(Class targetClass) {
            this.targetClass = targetClass;

            this.serializer = new StdScalarSerializer(targetClass) {
                @Override
                public void serialize(T value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
                    jgen.writeString(BaseProvider.this.toString(value));
                }
            };

            this.deSerializer = new StdScalarDeserializer(targetClass) {
                @Override
                public T deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
                    return of(p.getText())
                            .map(BaseProvider.this::fromString)
                            .orElse(null);
                }
            };
        }

        public T fromString(String value) {
            return of(value)
                    .map(ZonedDateTime::parse)
                    .map(this::toValue)
                    .orElse(null);
        }

        public String toString(T value) {
            return from(value).format(ISO_OFFSET_DATE_TIME);
        }
    }

    private static class LocalDateProvider extends BaseProvider {
        private static final Pattern YYYY_MM_DD_PATTERN = Pattern.compile("^\\d{4}-\\d{2}-\\d{2}$");

        private LocalDateProvider() {
            super(LocalDate.class);
        }

        @Override
        protected LocalDate toValue(ZonedDateTime zonedDateTime) {
            return zonedDateTime.toLocalDate();
        }

        @Override
        protected ZonedDateTime from(LocalDate value) {
            return value.atTime(NOON).atZone(DEFAULT_ZONE);
        }

        @Override
        public LocalDate fromString(String value) {
            return of(value)
                    .filter(this::isLocalDate)
                    .map(LocalDate::parse)
                    .orElseGet(() -> super.fromString(value));
        }

        private boolean isLocalDate(String dateString) {
            return YYYY_MM_DD_PATTERN.matcher(dateString.trim()).matches();
        }

    }

    private static class LocalDateTimeProvider extends BaseProvider {

        private LocalDateTimeProvider() {
            super(LocalDateTime.class);
        }

        @Override
        protected LocalDateTime toValue(ZonedDateTime zonedDateTime) {
            return zonedDateTime.withZoneSameInstant(DEFAULT_ZONE).toLocalDateTime();
        }

        @Override
        protected ZonedDateTime from(LocalDateTime value) {
            return value.atZone(DEFAULT_ZONE);
        }

        @Override
        public LocalDateTime fromString(String value) {
            return of(value)
                    .flatMap(this::tryParseLocalDateTime)
                    .orElseGet(() -> super.fromString(value));
        }

        private Optional tryParseLocalDateTime(String dateString) {
            try {
                return Optional.of(LocalDateTime.parse(dateString));
            } catch (DateTimeParseException parseException) {
                return Optional.empty();
            }
        }
    }

    private static class ZonedDateTimeProvider extends BaseProvider {

        private ZonedDateTimeProvider() {
            super(ZonedDateTime.class);
        }

        @Override
        protected ZonedDateTime toValue(ZonedDateTime zonedDateTime) {
            return zonedDateTime;
        }

        @Override
        protected ZonedDateTime from(ZonedDateTime value) {
            return value;
        }
    }

    private static class DateProvider extends BaseProvider {

        private DateProvider() {
            super(Date.class);
        }

        @Override
        protected Date toValue(ZonedDateTime zonedDateTime) {
            return Date.from(zonedDateTime.toInstant());
        }

        @Override
        protected ZonedDateTime from(Date value) {
            return ZonedDateTime.ofInstant(Instant.ofEpochMilli(value.getTime()), DEFAULT_ZONE);
        }

    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy