Jaxb Unmarshal Timestamp

jaxb unmarshal timestamp

JAXB can handle the java.util.Date class. However it expects the format:

"yyyy-MM-dd'T'HH:mm:ss" instead of "yyyy-MM-dd HH:mm:ss"

If you want to use that date format I would suggest using an XmlAdapter, it would look something like the following:

import java.text.SimpleDateFormat;
import java.util.Date;

import javax.xml.bind.annotation.adapters.XmlAdapter;

public class DateAdapter extends XmlAdapter<String, Date> {

private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

@Override
public String marshal(Date v) throws Exception {
return dateFormat.format(v);
}

@Override
public Date unmarshal(String v) throws Exception {
return dateFormat.parse(v);
}

}

You would then specify this adapter on your timestamp property:

import java.util.Date;

import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlAccessorType(XmlAccessType.NONE)
@XmlRootElement(name = "foo")
public final class Foo {
// Other fields omitted

@XmlElement(name = "timestamp", required = true)
@XmlJavaTypeAdapter(DateAdapter.class)
protected Date timestamp;

public Foo() {}

public Date getTimestamp() {
return timestamp;
}

public void setTimestamp(final Date timestamp) {
this.timestamp = timestamp;
}

}

Creating adapter for Timestamp for JAXB conversion

JAXB (JSR-222) implementations support java.util.Date and java.util.Calendar by default so you will not require an XmlAdapter for them. Classes like java.sql.Date, java.sql.Time, and java.sql.Timestamp will require an XmlAdapter. I would recommend separate adapters instead of trying to combine them into one.

Note

An XmlAdapter can be specified at the package level. When doe this way it applies to all mapped fields/properties on that type belonging to domain classes in that package. This can greatly reduce the amount of times you need to specify @XmlJavaTypeAdapter. You can read more about this approach on my blog.

  • http://blog.bdoughan.com/2012/02/jaxb-and-package-level-xmladapters.html

UPDATE

There are two properties named "publishDate" 
this problem is related to the following location:
at public java.sql.Timestamp Book.getPublishDate()
at Book
this problem is related to the following location:
at private java.sql.Timestamp Book.publishDate
at Book

By default JAXB treats public properties (get/set method pairs) and annotated fields as mapped. This is what's causing this part of the exception. You need to do one of the following:

  1. Annotate the get method instead of the field.
  2. Keep the annotation on the field and specify @XmlAccessorType(XmlAccessType.FIELD) on your class.

I have written more about this on my blog:

  • http://blog.bdoughan.com/2011/06/using-jaxbs-xmlaccessortype-to.html

JAXB marshalling dateTime to blank value when time not specified

While I wasn't allowed to modify the xsd file directly, what I didn't realize was that I could change how the classes themselves were generated through a bindings file. I wasn't using maven in this case, so it was a bit difficult to determine the solution. I was generating the classes by using a feature built into eclipse that generates jaxb classes from an xsd file.

I learned more about bindings files here

I'm not exactly sure where that file needs to be placed in respect to maven, but in doing it the eclipse way it doesn't matter - you get to specify where the bindings file is during the jaxb class generation wizard.

Once generated, you'll need to code your own xml adapter.

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.xml.bind.annotation.adapters.XmlAdapter;

public class CalendarDateTimeAdapter extends XmlAdapter<String, Date> {

//Sadly my specific situation requires me to strip the time off of all dateTime objects
//It's bad, but I didn't get to design the system, so this is the best compromise...
private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

@Override public Date unmarshal(String value) throws ParseException {
synchronized (sdf){
return sdf.parse(value);
}
}

@Override public String marshal(Date value) {
if(value == null) { return null; }
synchronized(sdf){
return sdf.format(value);
}
}
}

Make sure your classes match what you specified in your bindings file...

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jaxb:bindings>

<jaxb:bindings version="2.1"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc">

<!-- Prevent wrapping data types into JAXBElements. -->
<jaxb:globalBindings generateElementProperty="false">

<!-- Use java.util.Date instead of XMLGregorianCalendar. -->
<xjc:javaType name="java.util.Date" xmlType="xs:dateTime"
adapter="com.package.location.adapter.CalendarDateTimeAdapter"/>
<xjc:javaType name="java.util.Date" xmlType="xs:date"
adapter="com.package.location.adapter.CalendarDateAdapter"/>
<xjc:javaType name="java.util.Date" xmlType="xs:time"
adapter="com.package.location.adapter.CalendarTimeAdapter"/>

</jaxb:globalBindings>
</jaxb:bindings>

Then, when doing your marshalling, use the setAdapter function to use it.

private String marshallObject(MyObject myObject) throws JAXBException{
JAXBContext jaxbContext = JAXBContext.newInstance(MyObject.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.setAdapter(new CalendarDateTimeAdapter());
StringWriter sw = new StringWriter();
jaxbMarshaller.marshal(myObject, sw);
String output = sw.toString();
return output;
}

Now they'll resolve to Date objects instead of XMLGregorianCalendar objects. And apparently, Date objects work better than XMLGregorianCalendars...

I'm still perturbed that the unmarshalled xml that went in doesn't marshal to become the same xml going out, but at any rate, this is precisely what I did to make it all start working. I'm sure I've done something against convention here, and if I have, please let me know.

Again I remind readers that I'm not using maven, nor any kind of framework (e.g. SpringMVC).

Unmarshalling a date from an XML String to entity using JAXB

You can configure JAXB in many different ways. You have chosen Annotations to define the binding (this is allright, do not worry).

I strongle recommend you read about that technique first as there are a lot of pitfalls. Here is a link to a good tutorial. Here is the part in the tutorial which explains why your binding does not work: XmlAccessorType part

As for your specific issue:
In general you have to tell JAXB what and how to bind the java object to it's XML representation. If you do not do anything, then by default all public members of your class are bound (as you can read here).

Additionally you have chosen to annotate the getter method of your public member, which then just pushes the same variable twice to your XML which later causes the exception you see.

To fix your error, either specify a different mapping strategy for your class by putting e.g. (@XmlAccessorType(XmlAccessType.NONE)) before your class declaration or move the annotation from the getter method to the property.

By the way: Having a getter method and a public member variable does not make sense at all. So making your member variable private will also fix your issue with JAXB and be a lot better for your class design.

JAXB unmarshal wrapped list

Apologies for answering so late, but this is the first hit on Google if search for related problems so it might help anyway.

Yes, it is possible, using

@XmlElementWrapper

in combination

@XmlElement

See this example for more detailed info.

Can JAXB handle java.time objects?

In Java SE 8, JAXB has not been updated yet to support the java.time types.

Indeed, there is an issue related to this in the reference implementation.

You need to create and use an XmlAdapter to handle those types. Use an approach similar to that done with Joda-Time as described in this posting, JAXB and Joda-Time: Dates and Times.

You may be able to use this implementation of adapters for java.time.

How do you specify the date format used when JAXB marshals xsd:dateTime?

You can use an XmlAdapter to customize how a date type is written to XML.

package com.example;

import java.text.SimpleDateFormat;
import java.util.Date;

import javax.xml.bind.annotation.adapters.XmlAdapter;

public class DateAdapter extends XmlAdapter<String, Date> {

private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

@Override
public String marshal(Date v) throws Exception {
synchronized (dateFormat) {
return dateFormat.format(v);
}
}

@Override
public Date unmarshal(String v) throws Exception {
synchronized (dateFormat) {
return dateFormat.parse(v);
}
}

}

Then you use the @XmlJavaTypeAdapter annotation to specify that the XmlAdapter should be used for a specific field/property.

@XmlElement(name = "timestamp", required = true) 
@XmlJavaTypeAdapter(DateAdapter.class)
protected Date timestamp;

Using a xjb binding file:

<xjc:javaType name="java.util.Date" xmlType="xs:dateTime"
adapter="com.example.DateAdapter"/>

will produce the above mentioned annotation.

(By eventually adding the xjc namespace: xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc")

Unmarshal nested Map with Jaxb

I would recommend that you structure your XML like:

<exchangerate>
<date>2015-05-04</date>
<currency code="EUR">
<rate code="EUR">1</rate >
<rate code="GBP">0.73788</rate >
<rate code="USD">1.1152</rate >
</currency>
<currency code="GBP">
<rate code="EUR">1.35523</rate >
<rate code="GBP">1</rate >
<rate code="USD">1.51136</rate >
</currency>
<currency code="USD">
<rate code="EUR">0.8967</rate >
<rate code="GBP">0.66166</rate >
<rate code="USD">1</rate >
</currency>
</exchangerate>

and you have multiple Classes:

@XmlAccessorType(XmlAccessType.FIELD)
public class ExchangeRates {
@XmlJavaTypeAdapter(DateAdapter.class)
private Date date;

@XmlElement(name="currency")
private List<Currency> currencies = new ArrayList<>();

....
}

@XmlAccessorType(XmlAccessType.FIELD)
public class Currency {
@XmlAttribute
private String code;

@XmlElement(name="rate")
private List<Rate> rates= new ArrayList<>();

....
}

@XmlAccessorType(XmlAccessType.FIELD)
public class Rate {
@XmlAttribute
private String code;

@XmlValue
private Double value;

....
}


Related Topics



Leave a reply



Submit