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:
- Annotate the get method instead of the field.
- 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
"Unable to Acquire Application Service" Error While Launching Eclipse
Resizing Icon to Fit on Jbutton in Java
Populating Spring @Value During Unit Test
How to Generate the JPA Entity Metamodel
The Method Getdispatchertype() Is Undefined for the Type Httpservletrequest
Log4J: Log Output of a Specific Class to a Specific Appender
Why Does Double.Nan==Double.Nan Return False
Square Root of Bigdecimal in Java
Java Ioexception "Too Many Open Files"
Changing the Shapes of Points in Scatter Plot
Convert from List<Completablefuture> to Completablefuture<List>
Using Itextpdf to Trim a Page's Whitespace