Дата сериализации в Java - PullRequest
       50

Дата сериализации в Java

7 голосов
/ 22 сентября 2008

Я передаю некоторые объекты через веб-сервис, и некоторые из них содержат java.sql.Date. Поскольку у Date нет пустого конструктора, он не хочет сериализоваться.

Первая часть вопроса проста: как лучше всего провести свидание между клиентом и службой?

Вторая часть немного сложнее: как только я решу, как передавать даты, я, очевидно, могу объявить переходную дату и сделать некоторый класс-оболочку для передачи дат в виде String или чего-то еще, но как применить одно и то же решение максимально прозрачно для нескольких классов что включает в себя дату?

(Я догадываюсь, что DynamicProxy может быть решением, но чтение документации на сайте Sun не очень помогло, поэтому, если это действительно что-то в этом направлении, некоторые пояснения будут оценены)

Редактировать: Я задал неправильный вопрос, извините (какое-то недопонимание между мной и коллегой, что на самом деле является проблемой). Проблема возникает из-за десериализации. Поэтому, когда у меня есть дата в формате xml, она пытается десериализовать себя как GregorianCalendar. Остается еще одна часть вопроса: каков наилучший способ получить что-либо (длинная метка времени или GregorianCalendar) и преобразовать его в дату sql, не создавая 10 разных оболочек для 10 разных классов. Я использую NetBeans для генерации кода и wsdl.

Ответы [ 12 ]

8 голосов
/ 22 сентября 2008

Joda-Time

Класс Date имеет неуклюжий API. Лучшая реализация - Joda-Time .

ISO 8601

Joda-Time также позволяет конвертировать вашу дату в стандартный формат ISO 8601 (гггг-мм-ддТЧЧ: ММ: СС.ССС). Использование этого стандарта при перемещении дат с сервера на клиент имеет преимущество, заключающееся в включении полной даты в удобочитаемый формат. Когда вы используете, например, JAXB , представление даты в формате XML также является стандартом ISO. (см. класс XMLGregorianCalendar)

6 голосов
/ 22 сентября 2008

Сериализация long, возвращаемого Date.getTime (), как предложено ранее, будет работать. Однако следует помнить, что если ваш сервер находится в другом часовом поясе, чем клиент, дата, которую вы восстановите на другой стороне, будет другой. Если вы хотите восстановить точно такой же объект даты, вам также необходимо отправить свой часовой пояс (TimeZone.getID ()) и использовать его для восстановления даты на другой стороне.

3 голосов
/ 22 сентября 2008

Чтобы ответить на первую часть вашего вопроса, я бы предложил строку в формате iso 8601 (это стандарт для кодирования дат).

Что касается второй части, я не уверен, зачем вам нужен прокси-класс? Или почему вы должны расширить класс даты для поддержки этого. например. Разве ваш веб-сервис не знает, что определенное поле является датой, и выполняет ли преобразование из даты в строку и обратно? Мне нужно немного больше информации.

2 голосов
/ 22 сентября 2008

java.sql. Дата расширяет java.util.Date.

Просто используйте getTime (), чтобы получить из него длинное значение. Это может быть сериализовано, и новый java.sql.Date (long) или новый java.util.Date (long) построен из этого на другом конце.

1 голос
/ 20 января 2015

Я остановлюсь на правильном ответе от JeroenWyseur.

ISO 8601

Стандартный формат ISO 8601 является абсолютно лучшим способом сериализации значения даты и времени для обмена данными. Формат является однозначным, интуитивно понятным для людей разных культур и все более распространенным во всем мире. Легко читается как для людей, так и для машин.

2015-01-16T20:15:43+02:00
2015-01-16T18:15:43Z

В первом примере смещение на 2 часа опережает UTC. Во втором примере показано обычное использование Z («зулу») для обозначения UTC, сокращение от +00:00.

java.time

Классы java.util.Date & .Calendar, связанные с Java, общеизвестно хлопотны, сбивают с толку и имеют недостатки. Избежать их. Вместо этого используйте:

  • Пакет java.time, встроенный в Java 8, на основе Joda-Time, определенный JSR 310.

Пакет java.time заменяет своего предшественника, библиотеку Joda-Time .

По умолчанию обе библиотеки используют ISO 8601 как для синтаксического анализа, так и для генерации строковых представлений значений даты и времени.

Обратите внимание, что java.time расширяет формат ISO 8601, добавляя собственное имя часового пояса , например 2007-12-03T10:15:30+01:00[Europe/Paris].

Найдите в StackOverflow.com сотни вопросов и ответов с большим количеством обсуждений и примеров кода.

Избегайте отсчетов из эпохи

В некоторых других ответах рекомендуется использовать число, отсчет от эпоха . Этот подход не практичен. Это не самоочевидно. Он не читается человеком, что делает отладку хлопотной и неприятной.

Какое это число, целые секунды, которые обычно используются в Unix, миллисекунды, используемые в java.util.Date & Joda-Time, микросекунды, обычно используемые в базах данных, таких как Postgres, или наносекунды, используемые в java.time package ?

Какая из пары дюжин эпох , первый момент 1970 года использовался в Unix, год 1 использовался в .Net & Go, «январь 0, 1900» использовался в миллионах (миллиардах?) Excel & Lotus электронные таблицы, или 1 января 2001 года используется Какао ?

diagram of different resolution of time tracking

См. мой ответ на аналогичный вопрос для дальнейшего обсуждения.

LocalDate

Я передаю некоторые объекты через веб-сервис, и некоторые из них содержат java.sql.Date

Замена для ужасного java.sql.Date класса java.time.LocalDate.

Лучше всего полностью избегать унаследованного класса, но вы можете конвертировать туда и обратно, вызывая новые методы, добавленные к старому классу: myJavaSqlDate.toLocalDate()

Сериализация LocalDate

Класс LocalDate реализует Serializable. Таким образом, у вас не должно возникнуть проблем с автоматическим сериализацией, как маршалингом, так и демаршаллингом.


О java.time

Фреймворк java.time встроен в Java 8 и более поздние версии. Эти классы вытесняют проблемные старые устаревшие классы даты и времени, такие как java.util.Date, Calendar, & SimpleDateFormat.

Чтобы узнать больше, см. Oracle Tutorial . И поиск переполнения стека для многих примеров и объяснений. Спецификация JSR 310 .

Проект Joda-Time , теперь в режиме обслуживания , рекомендует выполнить переход на классы java.time .

Вы можете обмениваться java.time объектами напрямую с вашей базой данных. Используйте драйвер JDBC , совместимый с JDBC 4.2 или более поздней версии. Нет необходимости в строках, нет необходимости в java.sql.* классах.

Где получить классы java.time?

Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является полигоном для возможных будущих дополнений к java.time. Здесь вы можете найти некоторые полезные классы, такие как Interval, YearWeek, YearQuarter и more .

1 голос
/ 22 сентября 2008

одно предостережение с java.sql. Недавно меня поразило то, что в нем не хранятся части времени (часы, минуты, секунды и т. Д.) Только часть даты. если вам нужна полная отметка времени, вы должны использовать java.util.Date или java.sql.Timestamp

1 голос
/ 22 сентября 2008

Я изучил реализацию java.sql.Date и, как я вижу, java.sql.Date можно сериализировать как расширение java.util.Date.

0 голосов
/ 22 сентября 2008

Хммм ... Не могу придумать ни одной причины, по которой любой сериализованный экземпляр объекта (сериализованный через механизм Java по умолчанию) должен десериализовать себя как экземпляр другого класса, поскольку информация о классе должна быть неотъемлемой частью сериализованных данных. .

Так что это либо проблема вашей (де-) инфраструктуры сериализации, либо среда принимает любой «подобный дате» объект на «отправляющей стороне» (Calendar, java.util.Date и т. Д. - таким образом, java.sql. Дата также расширяет java.util.Date), «сериализует» ее в строку в некотором распространенном формате даты (поэтому информация о типе теряется) и «десериализует» ее обратно в объект календаря на принимающей стороне.

Так что я думаю, что самый простой способ добраться до java.sql.Date - это сделать

java.sql.Date date = new java.sql.Date(calendar.getTimeInMillis);

там, где вам нужна java.sql.Date, но получите GregorianCalendar обратно из "десериализации".

0 голосов
/ 22 сентября 2008

java.sql.Date уже реализует Serializable, поэтому нет необходимости его реализовывать: -)

Что касается вашего основного вопроса, я глубоко влюблен в JAXB, так как я могу превратить практически любой XML в объект, так что, возможно, вам стоит посмотреть на него.

0 голосов
/ 22 сентября 2008

Вы можете использовать кодировщик и декодировать для сериализации и десериализации ваших объектов.

Вот пример, который сериализует класс SWT Rectangle:

XMLEncoder encoder = new XMLEncoder(new FileOutputStream(file));
encoder.setPersistenceDelegate(
    Rectangle.class, 
    new DefaultPersistenceDelegate(new String[]{"x", "y", "width", "height"}));
encoder.writeObject(groups);
encoder.close();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...