在Java中序列化日期

时间:2008-09-22 12:32:37

标签: java web-services serialization date

我通过Web服务传递一些对象,其中一些包含java.sql.Date。因为Date没有空构造函数,所以它不希望序列化。

问题的第一部分很简单:在客户端和服务之间传递日期的最佳方法是什么?

第二部分有点棘手:一旦我决定如何传递日期,我显然可以声明日期瞬态并使一些包装类将日期作为String或其他任何方式传递,但如何将相同的解决方案尽可能透明地应用于几个类包括日期?

(我预感到DynamicProxy可能是一个解决方案,但在Sun的网站上阅读文档并不是很有帮助,所以如果它真的是朝这个方向发展的话,那将会有一些澄清)

编辑:我问了错误的问题,对不起(我和同事之间的一些误解实际上是一个问题)。由于反序列化而出现问题。因此,一旦我有xml格式的日期,它会尝试将自身反序列化为GregorianCalendar。问题的其他部分仍然存在:接收某些东西(长时间戳或GregorianCalendar)并将其转换为sql日期的最佳方式是什么,而不为10个不同的类制作10个不同的包装器。我正在使用NetBeans代码和wsdl生成。

12 个答案:

答案 0 :(得分:8)

约达时间

Date类有一个笨重的API。更好的实施是Joda-Time

ISO 8601

Joda-Time还允许您以ISO 8601标准格式(yyyy-mm-ddTHH:MM:SS.SSS)转换日期。将日期从服务器移动到其客户端时使用此标准有利于以可读格式包含完整日期。当您使用例如JAXB时,日期的XML表示也是此ISO标准。 (参见XMLGregorianCalendar类)

答案 1 :(得分:6)

如前所述,序列化由Date.getTime()返回的long将起作用。但是,您应该注意,如果您的服务器位于客户端以外的其他时区,则您在另一侧重建的日期将会有所不同。如果你想重建完全相同的日期对象,你还需要发送你的时区(TimeZone.getID())并用它来重建另一边的日期。

答案 2 :(得分:3)

要回答问题的第一部分,我建议使用iso 8601格式的字符串(这是编码日期的标准)。

对于第二部分,我不确定为什么需要代理类?或者为什么你必须扩展日期类来支持它。例如。你的网络服务不会知道某个字段是一个日期并从日期转换为字符串并返回自身吗?我需要更多信息。

答案 3 :(得分:2)

java.sql.Date扩展了java.util.Date

只需使用getTime()从中获取long值。这可以序列化,并在另一端从它构造一个新的java.sql.Date(long)或新的java.util.Date(long)。

答案 4 :(得分:1)

我已经研究了java.sql.Date的实现,因为我看到java.sql.Date是Serializable作为java.util.Date的扩展。

答案 5 :(得分:1)

对java.sql.Date的一个警告最近让我觉得它不存储时间部分(小时,分钟,秒等)只是日期部分。如果你想要完整的时间戳,你必须使用java.util.Date或java.sql.Timestamp

答案 6 :(得分:1)

我将通过JeroenWyseur扩展correct answer

ISO 8601

ISO 8601标准格式绝对是序列化数据交换的日期时间值的最佳方式。这种格式对于不同文化的人们来说是明确的,直观的,并且在世界各地越来越普遍。易于阅读的人和机器。

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

第一个示例的偏移量比UTC早两个小时。第二个示例显示Z(" Zulu")的常用用途,表示UTC,+00:00的缩写。

java.time

java.util.Date&与Java捆绑在一起的日历类是众所周知的麻烦,令人困惑和有缺陷的。避免他们。而是使用:

  • java.time包,内置于Java 8中,受JDA-Time的启发,由JSR 310定义。

java.time 包取代了它的前身Joda-Time库。

默认情况下,两个库都使用ISO 8601进行解析和生成日期时间值的字符串表示。

请注意,java.time通过附加proper name of the time zone来扩展ISO 8601格式,例如2007-12-03T10:15:30+01:00[Europe/Paris]

通过大量讨论和示例代码,在StackOverflow.com上搜索数百个问题和解答。

避免从纪元开始计数

其他一些答案建议使用一个数字,来自epoch的计数。这种方法不实用。这不是不证自明的。它不是人类可读的,使调试麻烦和令人沮丧。

它是哪个数字,Unix中常用的整秒,java.util.Date&中使用的毫秒数。 Joda-Time,Postgres等数据库中常用的微秒,或java.time package中使用的纳秒?

1970年在Unix中使用的couple dozen epochs,1970年的第一个时刻,.Net&去," 1900年1月0日"用于数百万(数十亿?)的Excel& Lotus电子表格,或者Cocoa使用的2001年1月1日?

diagram of different resolution of time tracking

有关更多讨论,请参阅my answer类似问题。

LocalDate

  

我通过Web服务传递一些对象,其中一些包含java.sql.Date

可怕的java.sql.Date课程的替代品是java.time.LocalDate

最好完全避免遗留类,但您可以通过调用添加到旧类的新方法来回转换:myJavaSqlDate.toLocalDate()

序列化LocalDate

LocalDate类实现Serializable。所以你应该没有问题,它会自动序列化,包括编组和解组。


关于 java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendar和& SimpleDateFormat

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310

现在位于Joda-Timemaintenance mode项目建议迁移到java.time类。

您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*类。

从哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuartermore

答案 7 :(得分:0)

首先,如果您使用的是Web服务,则意味着您要序列化为XML而不是常规Java序列化(但是其他一些库用于编组和解组)。所以问题是缺少一些信息。

其次,如果你可以控制你的InputStream& OutputStream尝试扩展ObjectOutputStream和ObjectInputStream并覆盖 replaceObject() resolveObject(),然后您可以实现java.sql.Date的序列化。

答案 8 :(得分:0)

您不需要默认构造函数(空)来序列化/反序列化日期(java.sql.Date或java.util.Date)。在反序列化期间,不会调用构造函数,但是对象的属性直接设置为来自序列化数据的值,并且您可以按原样使用该对象,因为它反序列化了。

答案 9 :(得分:0)

您可以使用编码器和解码来序列化和反序列化对象。

以下是序列化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();

答案 10 :(得分:0)

java.sql.Date已经实现了Serializable,因此无需实现它: - )

就你的主要问题而言,我非常喜欢JAXB,因为我几乎可以把任何XML变成一个对象,所以你可能值得花时间去研究它。

答案 11 :(得分:0)

嗯...想不出任何理由为什么任何序列化的对象 - 实例(通过默认的java机制序列化)应该将自身反序列化为另一个类的实例,因为类信息应该是序列化数据的固有部分

所以这是你的(de)序列化框架的问题,或者框架接受“发送端”上的任何“类似日期”的对象(Calendar,java.util.Date等 - 因此java.sql。日期也扩展java.util.Date),将它“序列化”为一些常见日期格式的字符串(因此类型信息丢失)并将其“反序列化”回接收端的Calendar对象。

所以我认为获取java.sql.Date的最简单方法是执行

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

你需要一个java.sql.Date但是从“反序列化”中获取GregorianCalendar。