简体   繁体   中英

Unexpected values when unmarshalling Date and Currency attributes using JAXB

I am trying to umarshall xml response to java pojo. Having issues with date and currency values while unmarshalling using jaxb

Results of unmarshalling, the currency field value not getting mapped(null) and date field is mapped to some numbers(like 1503979200000)

Could someone please let me know where I am going wrong? Thanks in advance for your help.

Below is my code: unmarshall code: JAXBContext jc = JAXBContext.newInstance(Item.class); Unmarshaller um = jc.createUnmarshaller(); Item output = (Item)um.unmarshal(soapMessage.getSOAPBody().extractContentAsDocument());

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;

...

}

Date value in XML is in the format of yyyy-MM-dd

Result after unmarshalling: amount = null docDate=1503979200000 dueDate=1503979200000 postingDate=1503979200000

tl;dr

  • Feature, not a bug.
  • Your number 1_503_979_200_000L is a count of milliseconds from 1970-01-01T00:00:00Z.

Tips:

  • Use java.time classes instead of legacy date-time classes.
  • Use ISO 8601 formats when serializing date-time values to text.

Count-from-epoch

Your java.util.Date object is being serialized as a count of milliseconds since the epoch reference moment of first moment of 1970 in UTC, 1970-01-01T00:00:00Z. Sometimes called Unix Time, or POSIX Time .

java.time

The java.util.Date class you are using is one of the terrible old date-time classes bundled with the earliest versions of Java. Do not use these classes! Years ago they were supplanted by the java.time classes built into Java 8 and later.

Specifically, Date was replaced by Instant . Both represent a moment in UTC , but Instant resolves to the finer level of nanoseconds rather than milliseconds.

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

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

According to the Answer on my Question , JAXB has not yet been updated for java.time . However, adapters are available, such as this one .

ISO 8601

The ISO 8061 standard defines practical useful formats for serializing date-time values as text. They are easy to parse by machine. They are easy to read by humans across cultures.

The java.time classes use these formats by default when parsing/generating strings.

Example app

Here is a simple little example app to demonstrate how to use the java.time class Instant .

We added the JAXB adapters for Java 8 Date and Time API (JSR-310) types library via Maven. We need this adapter for Instant as JAXB has not yet been updated for java.time types. Hopefully that update can happen if we see swifter development with the Jakarta EE organization.

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

First, our simple little business-object class Event with a pair of properties, when and description .

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 + '\'' +
                " }";
    }
}

Instantiate a business object.

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

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

Run our JAXB code.

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();
}

Results:

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

We see the standard ISO 8601 format was used in the XML, 2018-07-31T04:03:43.113356Z . The Z on the end means UTC , and is pronounced Zulu .

Much more readable than 1503979200000 ! 😀


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date , Calendar , & SimpleDateFormat .

The Joda-Time project, now in maintenance mode , advises migration to the java.time classes.

To learn more, see the Oracle Tutorial . And search Stack Overflow for many examples and explanations. Specification is JSR 310 .

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval , YearWeek , YearQuarter , and more .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM