Sourabh
Sourabh

Reputation: 1303

Creating adapter for Timestamp for JAXB conversion

I am currently trying the JAXB library for XML to POJO conversion. I have a class which as follows :

class Student {

 String name;
 Integer id;
 Date dateOfBirth;
 @XmlJavaTypeAdapter(TimeDateAdapter.class)
 Timestamp admitTime;

 //constructor and getter setters

}

Now I want to input these fields via XML. So I reproduce xml something like :

  <student>
    <name>Student 1</name>
    <id>123</id>
    <dob>29-02-1991</dob>
    <admitTime>231441321413</admitTime>
  </student>

So, as you might know it will throw an error saying it cannot convert Timestamp since there is no no-arg constructor in Timestamp class. So I will have to create an Adapter. So, I was wondering if there is a way of creating a generic adapter for Date, timestamp and maybe Calendar as well so that they can be unmarshalled and marshalled according to the implementation?

EDIT: I created an Adapter for marshalling and unmarshalling my java.sql.Timestamp object from and to xml. Here is the code :

import java.sql.Timestamp;

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

public class TimeDateAdapter extends XmlAdapter<String, Timestamp>{

    @Override
    public String marshal(Timestamp v) throws Exception {
        return v.toString();
    }

    @Override
    public Timestamp unmarshal(String v) throws Exception {
        return new Timestamp(Long.parseLong(v));
    }

}

Its giving me the following error :

Exception in thread "main" com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 3 counts of IllegalAnnotationExceptions
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
java.sql.Timestamp does not have a no-arg default constructor.
    this problem is related to the following location:
        at java.sql.Timestamp
        at public java.sql.Timestamp Book.getPublishDate()
        at Book
Class has two properties of the same name "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

    at com.sun.xml.bind.v2.runtime.IllegalAnnotationsException$Builder.check(IllegalAnnotationsException.java:102)
    at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:472)
    at com.sun.xml.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:302)
    at com.sun.xml.bind.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(JAXBContextImpl.java:1140)
    at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:154)
    at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:121)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:248)
    at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:235)
    at javax.xml.bind.ContextFinder.find(ContextFinder.java:432)
    at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:637)
    at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:584)
    at BookMain.main(BookMain.java:42)

Upvotes: 2

Views: 7045

Answers (2)

user11116209
user11116209

Reputation:

    import java.sql.Timestamp;
    import java.time.LocalDateTime;
    import java.time.format.DateTimeFormatter;

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

    public class TimestampAdapter extends XmlAdapter<String, Timestamp> {
    
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH.mm.ss.SSSSSS");

    @Override
     public Timestamp unmarshal(String value) throws Exception {
        return Timestamp.valueOf(LocalDateTime.parse(value, formatter));
    }

    @Override
    public String marshal(Timestamp timestamp) throws Exception {
        return timestamp.toLocalDateTime().format(formatter);
    }
}

Upvotes: 0

bdoughan
bdoughan

Reputation: 149017

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.


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:

Upvotes: 3

Related Questions