1

I have a grails app that sends xml generated from Java POJOs through a REST like API.

On the client side there is a Java client that uses the same Java POJOs (the same jar library is used in Grails and the Java client) created from the XML.

For some reason the date in the XML doesn't get to the Java POJO. How do I get it in? Is there some trick I'm missing? Grails gets the date from the database (the column is a timestamp type), the XML has the date and time, the POJO has type Date, but the getter for the time returns null on the client side.

Here's the POJO code:

@Entity
@Table(name = "MODEL_VIEW")
@XmlRootElement
public class Model implements Serializable {

    private static final long serialVersionUID = 1L;
    @Basic(optional = false)
    @Column(name = "MODEL_ID")
    @Id
    private BigInteger modelId;

    @Column(name = "LAST_MODIFIED")
    @Temporal(TemporalType.TIMESTAMP)
    private Date lastModified;

    public Model() {
    }

    public BigInteger getModelId() {
        return modelId;
    }

    public void setModelId(BigInteger modelId) {
        this.modelId = modelId;
    }

    public Date getLastModified() {
        return lastModified;
    }

    public void setLastModified(Date lastModified) {
        this.lastModified = lastModified;
    }

}

UPDATE

Here is the XML (generated by Grails, using the same Entity classes, described above, as the client):

<?xml version="1.0" encoding="UTF-8"?>
<list>
<model id="1046">
    <modelId>1046</modelId>
    <lastModified>2013-09-17 17:42:17.478 PDT</lastModified>
</model>

Here is the code on the client that creates the POJO from the XML:

public synchronized List<Model> getAllModels() {
    return targetModel.request(MEDIA_TYPE).get(new GenericType<List<Model>>(){});
}

// psuedo code that creates the "targetModel" object
    private final static String BASE_URL ="http://mybiz.com/myapp"; 
    private Client client = ClientBuilder.newClient();
    client.register(new HttpBasicAuthFilter(username,password));
    private WebTarget targetBase = client.target(BASE_URL);
    private WebTarget targetModel = targetBase.path("model");

This is using Java EE 7 and Jersey client 2.0

Jason
  • 11,709
  • 9
  • 66
  • 82
  • Can you share the xml, and how you transform from xml to pojo? –  Sep 18 '13 at 02:17
  • 1
    Look into this post: http://stackoverflow.com/questions/9520716/cxf-jaxrs-how-do-i-pass-date-as-queryparam – TP_JAVA Sep 18 '13 at 02:19
  • @SérgioMichels, done. I added xml and xml-to-pojo code. Thanks for any help! – Jason Sep 19 '13 at 18:56
  • @Jason Look the TP_JAVA link, you need to adapt the date format readed by Jersey or change your Grails API to send a date in the format that Jersey wants. –  Sep 19 '13 at 19:41
  • Yes, using XMLJavaTypeAdapter and a custom class to use as the adapter worked, but there was a special case: I needed to put the XMLJavaTypeAdapter on the getter instead of the variable declaration. See http://www.objectpartners.com/2010/01/25/using-jpa-and-jaxb-annotations-in-the-same-object/ and http://stackoverflow.com/questions/2519432/jaxb-unmarshal-timestamp – Jason Sep 19 '13 at 21:55

1 Answers1

1

The final solution was to create my own custom adapter per jaxb unmarshal timestamp

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.SSS z");

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

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

}

Then change the entity class to

@Entity
@Table(name = "MODEL_VIEW")
@XmlRootElement
public class Model implements Serializable {

    private static final long serialVersionUID = 1L;
    @Basic(optional = false)
    @Column(name = "MODEL_ID")
    @Id
    private BigInteger modelId;

    @Column(name = "LAST_MODIFIED")
    @Temporal(TemporalType.TIMESTAMP)
    private Date lastModified;

    public Model() {
    }

    public BigInteger getModelId() {
        return modelId;
    }

    public void setModelId(BigInteger modelId) {
        this.modelId = modelId;
    }

    @XmlJavaTypeAdapter(DateAdapter.class)
    public Date getLastModified() {
        return lastModified;
    }

    public void setLastModified(Date lastModified) {
        this.lastModified = lastModified;
    }

}

Notice the @XmlJavaTypeAdapter annotation on getLastModified(). It had to go on the getter because JPA and JAXB are both used. http://www.objectpartners.com/2010/01/25/using-jpa-and-jaxb-annotations-in-the-same-object/

Note, the @XmlJavaTypeAdapter annotation could be put in the package and it will then be applied to all Date types!

Community
  • 1
  • 1
Jason
  • 11,709
  • 9
  • 66
  • 82