Jan 25, 2010

Using JPA and JAXB Annotations in the Same Object

Recently, I started working on some projects where I had to prototype various service end point technologies, including REST and AMF.  During this process, I worked out a fairly nice prototype project template that makes setting up a project fairly simple and quick.  I plan to write about the template more fully in a forthcoming post, but for now wanted to share a small gotcha that took me a bit to figure out.

I’m using JPA for persistence and JAXB to produce XML to some of the end points.  I’ve also been using annotations to minimize the amount of XML configuration that I have to do.  Things were going really well, until I wanted to customize the XML representation of one of my domain object members as well as persist it.  The member was a date and I wanted a simple month-day-year display rather than JAXB’s default locale formatting.  I started out with:

@Entity
@XmlRootElement
public class Person implements Serializable {

  @Temporal(TemporalType.DATE)
  private Date birthDate;

  public Date getBirthDate() {
    return birthDate;
  }

  public void setBirthDate(Date birthDate) {
    this.birthDate = birthDate;
  }
}

This worked but when I retrieved my XML via the REST end point my dates looked like:

<birthDate>1987-11-01T00:00:00-06:00</birthDate>

Kind of ugly.  Since formatting dates is quite common in the problem domain that these technologies would eventually be used in, I decided to add an example of it to the prototype.  I wrote a quick date adapter class:

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

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

public class DateAdapter extends XmlAdapter<String, Date> {
 // the desired format
 private String pattern = "yyyy-MM-dd";

 public String marshal(Date date) throws Exception {
 return new SimpleDateFormat(pattern).format(date);
 }

 public Date unmarshal(String dateString) throws Exception {
 return new SimpleDateFormat(pattern).parse(dateString);
 }
}

And simplistically tried to set it up by adding the annotation to the member declaration.

@Entity
@XmlRootElement
public class Person implements Serializable {

  @Temporal(TemporalType.DATE)
  @XmlJavaTypeAdapter(value=DateAdapter.class)
  private Date birthDate;

  public Date getBirthDate() {
    return birthDate;
  }

  public void setBirthDate(Date birthDate) {
    this.birthDate = birthDate;
  }
}

When I went to marshall the object, I hit an IllegalAnnotationException.

Caused by: com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
Class has two properties of the same name "birthDate"

It took a bit to figure out what was going on, and there was surprisingly little information or examples that tried to do this sort of thing when I searched around.   Eventually, I figured out what might be obvious to some.  The trick is to separate the two types of annotations and only use the JPA annotation on the member declaration and the JAXB annotation on the accessor (get) method.  When I altered my code to this:

@Entity
@XmlRootElement
public class Person implements Serializable {

  @Temporal(TemporalType.DATE)
  private Date birthDate;

  @XmlJavaTypeAdapter(value=DateAdapter.class)
  public Date getBirthDate() {
      return birthDate;
  }

  public void setBirthDate(Date birthDate) {
    this.birthDate = birthDate;
  }

}

Everything started working as expected.  Hopefully this can be helpful to anyone that encounters a similar situation.

About the Author

Steve McCoole profile.

Steve McCoole

Principal Technologist

Steve is a Principal Technologist for Mobile Development at Object Partners where he has been focusing on developing an enterprise mobile development practice, delivering applications to client that include: Oracle Retail, The Tile Shop, St. Jude Medical, SICK USA and Donaldson Corporation.  He has over 32 years of experience developing solutions from embedded, mobile and large-scale Java Enterprise web applications for diverse clients including IBM, Sun, Novell, Best Buy and Thomson Reuters.

One thought on “Using JPA and JAXB Annotations in the Same Object

  1. Mark says:

    thank you this just fixed a problem i had been banging my head against for hours

  2. Anton says:

    I tried to mix JPA and JAXB too in my domain model. When I do marshalling of persistent objects I get an exception:

    org.jboss.arquillian.test.spi.ArquillianProxyException: javax.xml.bind.MarshalException : null [Proxied because : Original exception not deserilizable, ClassNotFoundException]
    at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:326)
    at com.sun.xml.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:251)
    at javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(AbstractMarshallerImpl.java:95)

    I found that due to JPA-proxying JAXB annotations must be placed at getter level and not at field level. Removing @XmlAccessorType(XmlAccessType.FIELD) solved my problem.

    Note: in this case JAXB will also require a setter, otherwise during unmarshalling it will attempt to access field directly and will throw the same exception. If you want to make a field read-only at api-level (but not for JAXB) simply define a setter as protected.

  3. Fabio says:

    Thank you for this post. This was taking my head for hours.

  4. Rafael says:

    no wasting time reading this, tank u !

  5. Volodymyr Stadnyk says:

    Thanks!
    Very helpful article!!!

    And the last paragraph costs as a gold, because saved my nerves 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *

Related Blog Posts
Using Conftest to Validate Configuration Files
Conftest is a utility within the Open Policy Agent ecosystem that helps simplify writing validation tests against configuration files. In a previous blog post, I wrote about using the Open Policy Agent utility directly to […]
SwiftGen with Image & Color Asset Catalogs
You might remember back in 2015 when iOS 9 was introduced, and we were finally given a way to manage all of our assets in one place with Asset Catalogs. A few years later, support […]
Tracking Original URL Through Authentication
If you read my other post about refreshing AWS tokens, then you probably have a use case for keeping track of the original requested resource while the user goes through authentication so you can route […]
Using Spring Beans in a Kafka Streams ExceptionHandler
There are many things to know before diving into Kafka Streams. If you haven’t already, check out these 5 things as a starting point. Bullet 2 mentions designing for exceptions. Ironically, this seems to be […]