Проблема 2038 года все еще происходит с Джексоном десериализации даты в Java 8

Просто у меня есть следующий класс, чтобы получить тело JSON, полученное из удаленного ответа для десериализации, до CreditCardDTO даты, полученной внутри exp_date, например, «0820» для 8/2010 и «0240» для 2/2040:

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.Date;

@JsonInclude(JsonInclude.Include.NON_EMPTY)
@JsonPropertyOrder(alphabetic = true)
public class CreditCardDTO {
    private String brand;
    private Date expirationDate;

    @JsonProperty("brand")
    public String getBrand() {
        return brand;
    }

    @JsonProperty("credit_card_type")
    public CreditCardDTO setBrand(String brand) {
        this.brand = brand;
        return this;
    }

    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ")
    @JsonProperty("expirationDate")
    public Date getExpirationDate() {
        return expirationDate;
    }

    @JsonFormat(pattern = "MMyy")
    @JsonProperty("exp_date")
    public CreditCardDTO setExpirationDate(Date expirationDate) {
        System.out.println(expirationDate);
        this.expirationDate = expirationDate;
        return this;
    }
}

Проблема в том, что если это до 2038 года, все в порядке, но как только данные после этой критической даты, это все равно происходит, данные возвращаются к 1941 году, я искал проблему и обнаружил, что этого не должно происходить в Java 8 : Почему программисту на Java нужно заботиться о ошибка 2038 года?, так что мне интересно, в чем тут проблема!

Джексон версия 2.8.0, Java 8 точно.


person Al-Mothafar    schedule 03.07.2017    source источник
comment
@AndyTurner так в чем проблема? Вы видите ссылку, о которой я упоминал. Класс Java Java хранит 64-битную длинную   -  person Al-Mothafar    schedule 03.07.2017
comment
Вы используете класс java.util.Date, который все еще принадлежит старому набору функций Java. Чтобы использовать преимущества Java 8, вам необходимо использовать классы из пакетов java.time.   -  person RealSkeptic    schedule 03.07.2017
comment
System.out.println(new java.util.Date(Long.MAX_VALUE)); give Sun Aug 17 08:12:55 CET 292278994 на Java 8. Так что вы можете проверить, как Джексон управляет Date преобразованием   -  person AxelH    schedule 03.07.2017
comment
Если что-то мы узнали из ошибки 2000 года, так это то, что не используйте двузначный формат года для передачи или хранения данных. Вы это делаете. Это означает, что он должен угадать, что 40 - это 2040, а не 1940. Прочтите документацию для SimpleDateFormat, чтобы узнать, как он это решит. И переключитесь на использование четырехзначного числа лет для передачи данных.   -  person RealSkeptic    schedule 03.07.2017
comment
@RealSkeptic, это имеет смысл, но все же я вижу внутри класса Date, который они используют долго, но примерно two-digit year этот урок должен быть извлечен из проблемы 2000 года, но я должен иметь дело с этим удаленным API, разработанным парнем в старом стиле, он сказал, что может Не меняю это из-за того, что он запущен в другом старом проекте.   -  person Al-Mothafar    schedule 03.07.2017
comment
Если бы вы предоставили простой минимальный воспроизводимый пример, вы бы заметили, что он просто воспроизводится с помощью new java.text.SimpleDateFormat("MMyy").parse("0240")Thu Feb 01 00:00:00 CET 1940. Подтверждающий комментарий RealSkeptic (кстати). Поэтому, если вы не можете обновить _ 3_, ты ****   -  person AxelH    schedule 03.07.2017
comment
Обратите внимание на часть SimpleDateFormat javadoc, которая говорит, что он выполняет [анализ двузначных лет], устанавливая даты в пределах 80 лет до и 20 лет после создания экземпляра SimpleDateFormat (отмечая, что 2040 год наступит более чем через 20 лет). Есть более важные вещи до и после.   -  person Andy Turner    schedule 03.07.2017
comment
@AxelH нет, это не дубликат!   -  person Al-Mothafar    schedule 03.07.2017
comment
В ответе содержится объяснение java.time.LocalDate и java.util.Date преобразования для 2-значного года. Как вы сказали, вы не можете обновить API, поэтому у вас нет решения здесь. Просто подождите 3 года, чтобы пройти 2040 год.   -  person AxelH    schedule 03.07.2017
comment
@AxelH, значит, это могла быть ошибка Джекона   -  person Al-Mothafar    schedule 03.07.2017
comment
Вы читаете комментарии? Это не ошибка. Это ожидаемый результат двухзначного преобразования года. Вначале это был плохой дизайн, просто чтобы сохранить 2 персонажа. Прочтите комментарии еще раз и следите за предлагаемыми исследованиями (связанными или нет).   -  person AxelH    schedule 03.07.2017
comment
@AxelH да, это не ошибка Джекона (не сказал, ошибка Джекона), я имел в виду, что это может быть моя ошибка с плохим дизайном, как то, что вы сказали, которая ограничена способностями Джексона, а не ошибка с Джексоном, но я должен найти по-другому, или просто скажите этому парню, чтобы он как-то исправил этот плохой API. извините за путаницу (в моем английском много ошибок: D) Я мог бы использовать java.time.YearMonth как например   -  person Al-Mothafar    schedule 03.07.2017
comment
Если вы не можете изменить формат даты истечения срока на 4-значный год, вам, возможно, придется проверить дату самостоятельно и добавить 100 лет при некоторых условиях, которые вам придется выяснить (не просто делайте это, если дата в прошлом, или кредитные карты никогда не истекают). Добавить 100 лет проще с java.time API. Я считаю, что вы можете использовать его с Джексоном, если получите jackson-datatype-jsr310.   -  person Ole V.V.    schedule 03.07.2017
comment
Действительно ли у людей есть даты кредитных карт более чем на 20 лет вперед? Разве это не то, что вы могли бы решить с помощью проверки в другом месте?   -  person Andy Turner    schedule 03.07.2017
comment
@AndyTurner для большинства случаев использования не более 20 лет, в любом случае это здесь stackoverflow.com/questions/2500588/   -  person Al-Mothafar    schedule 03.07.2017


Ответы (1)


Хотя я не знаю о Джексоне, я могу сказать вам, что вы проявили плохой подход к обработке данных об истечении срока действия кредитной карты.

Во-первых, вы решили действовать самостоятельно, а не смотреть на существующие классы и стандарты. Всегда ищите предыдущую работу; Самостоятельный подход должен быть последним средством, а не первым. Меньше дикого ковбоя, больше судьи, руководствующегося прецедентами.

Во-вторых, вы используете старые устаревшие классы даты и времени, которые теперь вытесняются классами java.time.

YearMonth

Чтобы представить год и месяц, используйте YearMonth < / a> класс, встроенный в Java. Месяцы пронумерованы разумно, с 1 по 12 за январь-декабрь, в отличие от унаследованных классов.

YearMonth ym = YearMonth.of( 2040 , 3 ) ; 

Кстати, перечисление Month может вам пригодиться в вашей работе.

YearMonth ym = YearMonth.of( 2040 , Month.MARCH ) ; 

Используйте этот YearMonth класс в качестве своего члена, а не на конкретную дату.

Сравнивая с такой датой, как сегодня, получите YearMonth для этой даты.

ZoneId z = ZoneId.of( "Asia/Amman" ) ;
LocalDate today = LocalDate.now( z ) ;
YearMonth ymToday = YearMonth.from( today ) ;

Boolean isExpired = ymToday.isAfter( ym ) ;

ISO 8601

Стандарт ISO 8601 определяет множество практичных форматов для представления значений даты и времени в виде текста.

Стандартный формат для года-месяца - YYYY-MM. Итак, март 2040 года 2040-03.

Классы java.time по умолчанию используют стандартные форматы при синтаксическом анализе или генерации строк.

Сгенерируйте строку.

ym.toString()  

2040-03

Разобрать строку.

YearMonth ym = YearMonth.parse( "2040-03" );

Всегда используйте 4-значные годы

Как для хранения, так и для представления всегда используйте четыре цифры года. Бесконечная путаница, ошибки и двусмысленность не стоят того, чтобы экономить два октета памяти / хранилища или полсантиметра места на бумаге.

person Basil Bourque    schedule 03.07.2017
comment
Спасибо за ответ, вроде как я слежу за тем, что вы говорите, как я уже сказал, ответ от удаленного API не является моей проблемой, и этот разработчик достаточно тупой, чтобы отклонить мой запрос на изменение года, поскольку я нашел решение для используйте либо YearMonth, либо оставьте свой собственный способ использования ISO 8601 и ограничьте форму до +20 лет от максимума, похоже, синтаксический анализ с Джексоном использует SimpleDateFormat для синтаксического анализа 'yy'. - person Al-Mothafar; 03.07.2017