使用JAXB解组Date和Currency属性时出现意外值



我正在尝试umarshall xml对java pojo的响应。使用jaxb-解组时出现日期和货币值问题

解组的结果是,货币字段值没有被映射(null),日期字段被映射到一些数字(如1503979200000)

有人能告诉我哪里出了问题吗?提前感谢您的帮助。

以下是我的代码:解组代码:JAXBContext jc=JAXBContext.newInstance(Item.class);Unmarshaller um=jc.createUnmarshaler();项目输出=(Item)um.unmarshal(soapMessage.getSOAPBody().textractContentAsDocument());

Pojo:

@XmlRootElement( name = "item" )
@XmlAccessorType(XmlAccessType.FIELD)  
public class Item{
@XmlElement( name = "bl" )
@XmlJavaTypeAdapter(DateTimeAdapter.class)
private Date docDate;
@XmlElement( name = "sd" )
@XmlJavaTypeAdapter(DateTimeAdapter.class)
private Date dueDate;
@XmlElement( name = "bu" )
@XmlJavaTypeAdapter(DateTimeAdapter.class)
private Date postingDate;
@XmlElement( name = "wr" )
@XmlJavaTypeAdapter(CurrencyAdapter.class)
private Currency amount;
...

}

XML中的日期值的格式为yyyy-MM-dd

解组后的结果:amount=null docDate=1503979200000 dueDate=150397920 0000 postingDate=15039729200000

tl;dr

  • 功能,而不是bug
  • 您的数字1_503_979_200_000L是从1970-01-01T00:00:00Z开始的毫秒计数

提示:

  • 使用java.time类,而不是传统的日期-时间类
  • 将日期时间值序列化为文本时,请使用ISO 8601格式

从epoch开始计数

您的java.util.Date对象被序列化为自1970年第一个时刻(UTC,1970-01-01T00:00:00Z)的历元参考时刻以来的毫秒数。有时称为Unix时间或POSIX时间。

java.time

您正在使用的java.util.Date类是与最早版本的Java捆绑在一起的糟糕的旧日期时间类之一。不要使用这些类!几年前,它们被java 8及更高版本中内置的java.time类所取代。

具体而言,DateInstant取代。两者都表示UTC中的一个时刻,但Instant解析为更精细的纳秒级,而不是毫秒级。

long input = 1_503_979_200_000L;
Instant instant = Instant.ofEpochMilli( input  );

instant.toString():2017-08-29T04:00:00Z

根据我的问题回答,JAXB还没有为java.time更新。但是,适配器是可用的,比如这个。

ISO 8601

ISO 8061标准定义了将日期时间值序列化为文本的实用格式。它们很容易被机器解析。它们很容易被不同文化的人阅读。

在解析/生成字符串时,java.time类默认使用这些格式。

示例应用程序

这里有一个简单的小示例应用程序来演示如何使用java.timeInstant

我们通过Maven为Java 8日期和时间API(JSR-310)类型库添加了JAXB适配器。我们需要Instant的这个适配器,因为JAXB还没有针对java.time类型进行更新。如果我们看到JakartaEE组织的更快发展,希望更新能够发生。

<dependency>
<groupId>com.migesok</groupId>
<artifactId>jaxb-java-time-adapters</artifactId>
<version>1.1.3</version>
</dependency>

首先,我们的简单小业务对象类Event具有一对属性whendescription

package com.basilbourque.example;
import com.migesok.jaxb.adapter.javatime.InstantXmlAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import java.time.Instant;
public class Event {
private Instant when;
private String description;
// ---------------|  Constructors  |-------------------------
public Event ( Instant when , String description ) {
this.when = when;
this.description = description;
}
// ---------------|  Accessors  |-------------------------
@XmlJavaTypeAdapter ( InstantXmlAdapter.class )
public Instant getWhen () {
return when;
}
public void setWhen ( Instant when ) {
this.when = when;
}
public String getDescription () {
return description;
}
public void setDescription ( String description ) {
this.description = description;
}
// ---------------|  Object  |-------------------------
@Override
public String toString () {
return "Event{ " +
"when=" + when +
", description='" + description + ''' +
" }";
}
}

实例化业务对象。

Event e = new Event( Instant.now() , "Devoxx" );
System.out.println("e.toString(): " + e);
System.out.println(""); // blank line.

e.toString():事件{when=2018-07-31T04:03:343.113356Z,description='Devoxx'}

运行我们的JAXB代码。

try {
JAXBContext jc = JAXBContext.newInstance( Event.class );
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT , true );
JAXBElement< Event > jaxbElement = new JAXBElement< Event >( new QName( "event" ) , Event.class , e );
marshaller.marshal( jaxbElement , System.out );
} catch ( JAXBException e1 ) {
e1.printStackTrace();
}

结果:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<event>
<description>Devoxx</description>
<when>2018-07-31T04:03:43.113356Z</when>
</event>

我们看到XML中使用了标准的ISO 8601格式2018-07-31T04:03:43.113356Z。末尾的Z表示UTC,发音为Zulu

1503979200000可读得多!😀


关于java.time

java.time框架构建在Java8及更高版本中。这些类取代了诸如java.util.DateCalendar和&CCD_ 18。

现在处于维护模式的JodaTime项目建议迁移到java.Time类。

要了解更多信息,请参阅Oracle教程。并在Stack Overflow中搜索许多示例和解释。规范是JSR310。

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

从哪里获得java.time类?

  • Java SE 8Java SE 9和更高版本
    • 内置
    • 标准Java API的一部分,带有捆绑实现
    • Java 9添加了一些小功能和修复程序
  • Java SE 6Java SE 7
    • 大部分Java.time功能都是向后移植到Java 6&7英寸ThreeTen背包
  • Android
    • java.time类的Android捆绑包的后续版本
    • 对于早期的Android(<26),ThreeTenABP项目适用于ThreeTen Backport(如上所述)。请参阅如何使用ThreeTenABP…

ThreeTen Extra项目通过附加类扩展java.time。这个项目是将来可能添加到java.time的试验场。您可以在这里找到一些有用的类,如IntervalYearWeekYearQuarter等等。

最新更新