Exposing Domain Models through the RESTful Service Interface, Part 1 Blog

Version 2


    Suppose you have a domain model represented by a set of classes annotated @Entity Beans and you would like to expose this model through a RESTful web service. There are several ways of doing this, including the Java way that goes by the name of Jersey API. Good choice, but as soon as you create your first web service you will notice that Jersey uses JAXB (Java Architecture for XML Binding) to serialize Java objects in XML documents, and you will also realize that JAXB and JPA (Java Persistence API) are not easy to combine. This article demonstrates how to combine JAXB and JPAto transfer data between the database and the web service interface without any adapter code in the middle, while preserving the authorization mechanism for sensitive information.

    The article is example-driven, guiding you step-by-step through code snippets and highlighting the adaptation required to produce the confluence between JPA and JAXB annotations. The code sample included in the article is a snapshot of the Footprint Service Project, an open source project (LGPL license) that supports the distribution of certificates of participation in conferences. The purpose of using a real project instead of toy examples is to guarantee that you are working with tested software and to give you the opportunity to discuss further questions with the project team. The full source code of the project is available in the Subversion repository, but a pre-compiled EAR file is provided to shorten the steps required to run and test the project. Note that code retrieved from the repository will vary as the project developers make new commits. Refer to the Resources section of this article for instructions on running the project.

    The Domain Model of Conference Certificates

    The full Footprint model is too large to be covered in this article; instead, I focus in a small subset of the problem, being careful not to miss the important details. For now, let's concentrate on a 1:n relationship between the conference attendees and their certificates of participation, as shown in the Figure 1.

    Serialization Mismatch
    Figure 1. The relationship between users and their certificates

    Using an open-source project for the examples lets you check out and experiment with a large code set rather than just a few simple cases.

    Applying JAXB @XML Annotations to the JPA @Entity Beans

    The first step is to design how the persistence layer will be accessed from the other layers of your Java EE application. Despite the possibility of using the EntityManager injected in your business layer, I prefer to follow the classical Design Access Object (DAO) pattern in order to have a centralized data access layer. The idea is to have a CRUD (Create, Read, Update, Delete) interface shared by all entities, and to have sub-interfaces extending the CRUD with specialized business methods. To enable using dependency injection, and to allow the container to manage the allocation of the DAO classes, I coded it as an EJB 3.0 Stateless Session Bean, as shown in the steps below.

    1. Create a Package Containing the JPA Entities and thepackage-info.java File

    JSR 175recommends package-info.java for package-level annotations, and in our case it is very important to have a namespace applied to all entities. For example:

     @XmlSchema( namespace = "http://footprint.dev.java.net/service/entity") @XmlAccessorType(XmlAccessType.FIELD) package net.java.dev.footprint.service.entity; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlSchema;

    The choice of the XmlAccessorType should parallel the JPA annotations. If you are annotating the fields of your class as JPA columns, use XmlAccessType.FIELD; otherwise use XmlAccessType.PROPERTY. The default value is XmlAccessType.PUBLIC_MEMBER. This causes problems if you declare a field and create its respective get method. The JAXB will assume the class has two fields with the same name and will throw a an exception:com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions.

    2. Implement the Domain Model

    All entities should have a version number and a unique identifier, so we start the domain model implementation with a @MappedSuperclass Entity, abstract and serializable as a XML complex type. Here is the complete Footprint entities superclass code:

     import java.io.Serializable; import javax.persistence.*; import javax.xml.bind.annotation.*; @
    XmlType @
    MappedSuperclass public abstract class AbstractFootprintEntity implements Serializable { @Transient public static final long serialVersionUID = 196919661993L; @
    XmlAttribute @
    Version private int version; @
    XmlElement @
    Id @
    GeneratedValue private long id; public long getId() { return id; } public void setId(long id) { this.id = id; } public int getVersion() { return version; } }

    Some important notes about this code:

    1. Use XmlType to serialize mapped super classes because you will not use this type as an XML root element. That class will be more useful as a parameter in Genericsmethods.
    2. Our superclass is Serializable because Detached Entities must implement the Serializable interface. When entities are serialized in XML documents they become detached entities.
    3. Always declare a @Version attribute and serialize this attribute in the XML documents. This is used by the Optimistic Concurrency Control of JPA and it is especially relevant to detached objects exposed through web services. Not only will the entity instance be detached, but the entity manager instance will be different between the stateless service calls. The only chance to detect conflicts between concurrent updates is through the versioning of the entities. Another important point is the absence of the setVersion(int) method. This is because the version field reflects its respective database column, modifiable only by JPA.
    4. Never annotate a field with name id as@XmlAttribute because xml:id is a defined attribute in XML documents and should be unique. Another JPA best practice: all entities should have an ID attribute. As a rule of thumb, never use a name from the XML specification as an entity's field name. A simple trick if XML is not your mother tongue: compile the schema from your annotated classes and check if it passes the W3C XML Schema Validator.
    5. The annotation @Transientis redundant in the field serialVersionUID since class members are neither serialized by JAXB nor persisted by JPA. The annotation serves to remind you that you can suppress any field from both persistence and serialization if needed. We declared theserialVersionUID public to reuse its value in the entity subclasses.
    6. The order of the fields in the serialization will match their order in the class declaration. You can optionally use the annotation@XmlAccessorOrder(XmlAccessOrder.ALPHABETICAL) to force an alphabetical order, but if you use schemagenor some other tool to compile those classes in an XSD schema, the order will reflect your choice. It is more a matter of style than a technical issue, so I prefer configuring through the fields' order.
    3. Create the Entity Beans

    Below is the code for two related entities from the Footprint model. First is the entity that represents the user table:

     import java.util.*; import javax.persistence.*; import javax.xml.bind.annotation.*; @XmlRootElement @Entity public class FpUser extends FpAbstractUser { private static final long serialVersionUID = AbstractFootprintEntity.serialVersionUID; @XmlElement @Column(nullable = false) private String name; @XmlElement @Column(nullable = true) private String email; @XmlTransient @OneToMany(mappedBy = "user", cascade = CascadeType.ALL) private List<FpCertificate> certificate; public List<FpCertificate> getCertificate() { if (certificate == null) { certificate = new ArrayList<FpCertificate>(); } return certificate; } public void setCertificate(List<FpCertificate> certificate) { this.certificate = certificate; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getName() { return name; } public void setName(String name) { this.name = name; }

    The conversion of simple JPA attributes in JAXB serializable fields is simple: just add the annotation @XmlElementor @XmlAttribute, depending on the how you want the information to appear in the output XML. The trickiest part is to convert the relationship between entities in JAXB serializable fields, as you can see in the annotation @XmlTransienton the certificate field. Before discussing that, let's check the code from the owner side of the relationship: theFpCertificate class.

     import javax.persistence.*; import javax.xml.bind.annotation.*; @XmlRootElement @Entity public class FpCertificate extends AbstractFootprintEntity { private static final long serialVersionUID = AbstractFootprintEntity.serialVersionUID; @XmlElement @ManyToOne(fetch = FetchType.EAGER,cascade = CascadeType.ALL) @JoinColumn(name = "user_id") private FpAbstractUser user; @XmlElement @Column private String path; public FpAbstractUser getUser() { return user; } public void setUser(FpAbstractUser user) {this.user = user; } public String getPath() { return path; } public void setPath(String path) {this.path = path; } }
    JAXB Annotations on the Relationships Between JPA Entities

    If you just try to add the @XmlElement annotation on top of your @Column fields, JAXB will throw a circular reference exception trying to serialize the objects into XML documents. The workaround for that problem is to annotate one side of a relationship with the JAXB @XmlTransientannotation, as we did in the FpUser class above. Notice that we are removing the relationship between the entities when we serialize them into XML documents. That results in two different views on the same domain model: the full domain model mapped by the JPA Entities and a partial view of the domain model mapped by the JAXB types. Though scary at first, that strategy preserves the original domain model and causes no problem in our application. Another important aspect to observe is the graph of objects in memory against the data transfer between the service and its clients. When we think about how to expose the data on the service interface, we soon realize that the complete object graph representing a relationship in the domain model may be just too much to serialize in a service response. Imagine if an instance ofFpUser has 200 associated certificates and a service call requests the information about the user name. In the domain model, a user contains a list of certificates, but our request needs only the name of the user. So, the decision of which information our service will expose on which method is beyond the technical aspects of annotation. A good practice in RESTful design is to implement complex use cases with several fast small calls instead of a single slow call that transports large amounts of data. In our example, the FpCertificate entities will be completely serialized, but the FpUser entities will be serialized without information about their certificates. We need to create a second method to receive the ID of theFpUser and then return the list of the user's certificates.

    Our exercise in defining the visibility of the domain model through the web services starts with the definition of which links we should mark as transient in the JAXB types. The strategy I used to avoid circular references in the JAXB types is summarized in the table below:

    RelationshipOwnerInverse Side

    Another way to manage the visibility of the domain model data on the service interface is through the JPA Lazy Loading. The default loading strategy of JPA isFetch.LAZY, while the JAXB framework expects a graph of objects already loaded in memory. So, if you just serialize an @Entity object with JAXB, any lazy-loaded reference to other entities will appear blank on the output XML, and we want to avoid the use of getters and setters during our magic conversion between entities and XML elements. The workaround for that is to change the field loading to EAGER, modifying the JPA annotation, as shown in the FpCertificate code. It may produce a larger result set and may impact the application performance, so you should use it only when you know in advance that the size of the resultant objects graph is acceptable. Otherwise just leave theFetch.LAZY and force the client to do a second service call to compose the object graph by parts.

    Now that we have our model annotated by JAXB, we can use the entities both for persistence and for serialization without any other modification. In the next section I show the code of a Data Access Layer used by the web service to expose the domain model on the web.

    A Generic CRUD Facade for your @Entity Beans

    You can use several strategies to integrate the persistence layer with the controller layer, including the injection of the EntityManager in the controller classes or the adoption of the Data Access Object pattern. I chose the DAO option, and the steps below enumerate the implementation of the data access layer as a set of EJB 3.0 Stateless Beans.

    1. Define the CRUD Interface

    Define a CRUD interface that can handle the common persistence operations with our entities. Notice the count method, useful for pagination.

     import java.io.Serializable; import java.util.*; import javax.persistence.*; public interface FpEntityFacade<T extends AbstractFootprintEntity> { T 
    create(T entity) throws Exception;

    T read(Serializable primaryKey) throws Exception;

    T update(T entity) throws Exception;

    void delete(T entity) throws Exception;

    Collection<T> readAll(int start, int size) throws Exception;

    long count() throws Exception;
    2. Define the CRUD Sub-interface

    Define the CRUD sub-interface, one for each Entity. Notice that those interfaces can add business operations to the inherited CRUD ones, as suggested in the comments.

     @Remote public interface FpUserFacade extends FootprintEntityFacade<FpUser> { 
    // void changeRating(FpEvent event, int newRating); } @Remote public interface FpCertificateFacade extends FpEntityFacade<FpCertificate> { }


    3. Implement the CRUD Interface

    Now we implement our CRUD interface. Here, the only trick is the reflection used in the constructor to catch the class of the entity; this avoids the need to include the type of the entity every time we construct a new facade. Also observe theEntityManager injected in the bean, which characterizes those beans more as Entity Manager Wrapperthan DAO, actually.

     import java.io.Serializable; import java.util.*; import javax.ejb.Stateless; import javax.persistence.*; import net.java.dev.footprint.service.entity.*; @Stateless public abstract class CRUDEntityFacade<T extends AbstractFootprintEntity> implements FpEntityFacade<T> { private transient final Class<T> entityClass; @PersistenceContext(name = "footprint") protected transient EntityManager manager; @SuppressWarnings("unchecked") public CRUDEntityFacade() { entityClass = (Class<T>) ((java.lang.reflect.ParameterizedType) this.getClass().getGenericSuperclass()) .getActualTypeArguments()[0]; } public T create(final T entity) throws Exception { manager.merge(entity); manager.flush(); return entity; } public Collection<T> readAll(int offset, int limit) throws Exception { if (offset < 0) { offset = 0; } if (limit <= 0 || limit > 50) { limit = 50; } Query query; query = manager.createQuery("select e from " + entityClass.getSimpleName() + " e"); query.setFirstResult(offset); query.setMaxResults(offset + limit); return doQuery(query); } public T read(final Serializable primaryKey) throws Exception { return manager.find(entityClass, primaryKey); } public void delete(final T entity) throws Exception { manager.remove(entity); manager.flush(); } public T update(final T entity) throws Exception { return manager.

    public long count() throws Exception {
    Query query =
    manager.createQuery("select count(e.id) from "
    + entityClass.getSimpleName() + " e");
    Number countResult = (Number) query.getSingleResult();
    return countResult.longValue();

    As you notice in the above code, the update method is an important illustration of exposing domain models through the service interface. All objects transfered between the client and the service are JPA Detached Objects, so you can merge the modified data back into the database only if the version of the detached object is the same as the version number stored in the database. That will not work in two cases:

    1. The partial graph of objects: if you try, for example, to merge the serialized FpUser entities back in the database, it will work, but it will delete the relationship betweenFpUser and FpCertificate, insertingnull into the relationship column.
    2. Under concurrency: the serialized entities contain a version number, which will not always represent the latest version of the entity in the database, and the attempt to merge an entity with a different version number will throw a JPA exception.

    So you will be forced to load the original entity, copy programatically the new data from the incoming object to the original entity object, and finally call the merge operation of JPA. It is an unavoidable procedure, and the general approach for doing that is to use reflection-based APIs like the commons beanutils.

    Implement the CRUD Sub-interfaces

    Next, implement the CRUD sub-interfaces. It is important to notice here the safe update method overriding the generic one. The same should be done to the FpCertificate and the other entities. Another important aspect is that we exclude the relationship from this safe copy. It works if your detached entity comes with complete and valid information from outside the service interface, but for security reasons it is better to update the relationship between entities only through specialized business methods. Imagine, for example, if someone starts to manipulate the entities relationship outside the service interface and your facade just inserts it back into the database without filters; it's just too dangerous. Nevertheless, it is important to state that a merge of relationships works out of the box, and eventually it can be useful if the client is another service in the same security zone.

    A special remark about the delete operation in theparent-child relationship betweenFpCertificate and FpUser: deletion of anFpCertificate entity (child) requires no extra code, but deletion of an FpUser entity (parent) requires a bulk operation, because JPA does not propagate the deletion of a parent to its children. You need to delete the foreign key references to an FpUser entity before deleting it; otherwise, the bulk operation will be rolled back. [Special note: if you apply Hibernate, you can use CascadeType.DELETE_ORPHAN; using TopLink, you have the option to configure the relationships as private-owned. I didn't apply such features because they are both proprietary, but I expect such functionality to be included in a next EJB/JPA specification.]

     @Stateless public class UserFacade extends CRUDEntityFacade<FpUser> implements FpUserFacade { @Override public FpUser update(FpUser entity) throws Exception { FpUser attached = manager.find(FpUser.class, entity.getId()); 
    // this can be done with Commons BeanUtils
    return manager.merge(attached);

    public void delete(long id) throws IllegalStateException,
    IllegalArgumentException, TransactionRequiredException,
    PersistenceException {
    Query query = manager.
    query.setParameter(FpCertificate.USER_ID_PARAM, id);
    FpUser user = manager.find(FpUser.class, new Long(id));

    public class CertificateFacade
    extends CRUDEntityFacade<FpCertificate>
    implements FpCertificateFacade {
    public FpCertificate update(FpCertificate entity)
    throws Exception {
    FpCertificate attached =
    manager.find(FpCertificate.class, entity.getId());
    return manager.merge(attached);

    Exposing the Domain Model in the RESTful Interface

    Our domain model is ready to be exposed on the web. Below you find an example of a Jersey annotated resource that exposes theFpUser entities in their service end points (logging and exception handling were removed for the sake of clarity). Observe how few lines of code are required to traverse the data directly from the database to the service endpoint without any copy (unless for the update method explained above). Another important aspect is the security of the CRUD operations: it is the responsibility on the service implementation to check if the client or the authenticated user is allowed to access the referred entities; here I am just showing the raw code, but in a production environment one should include business validation on the service interface.

     import java.util.*; import javax.ejb.EJB; import javax.ws.rs.*; import javax.xml.bind.*; import net.java.dev.footprint.service.entity.*; import static javax.ws.rs.core.MediaType.*; @Path("/user") public class UserResource { @EJB private FpUserFacade userFacade; @Produces( { APPLICATION_XML, APPLICATION_JSON }) @Consumes( { APPLICATION_XML, APPLICATION_JSON }) @PUT @Path("/create") public FpUser 
    create(FpUser newUser) {
    return FpUser user = userFacade.create(newUser);

    public FpUser read(@PathParam("id") String id) {
    userFacade.read(new Long(id)));

    public FpUser update(FpUser user) {
    return userFacade.update(user);

    public void delete(@PathParam("id") String id) {
    FpUser user = userFacade.read(id);

    public Collection<FpUser> editAll(
    @PathParam("offset") int offset
    , @PathParam("limit") int limit) {
    return userFacade.readAll(offset, limit);

    Observe the nice Jersey feature of exposing the data in two different formats: XML and JSON. Note that the client should include the HTTP header Accept:application/json to receive the data in JSON format.

    Installing and Testing the Sample Service

    The code presented in this article is a snapshot of the Footprint Service Project. In order to install and test the sample project, do the following:

    1. Install and configure Java Standard Edition 6
    2. Install and configure Glassfish v2.1
    3. Download the sample EAR file
    4. Open a console and execute the following commands:
       asadmin start-database asadmin start-domain domain1 asadmin deploy --user admin --password adminadmin footprint-service-ear-1.0-SNAPSHOT.ear

    Once you've done this, you can test the application opening the URLs below in a web browser. To invoke the POST,PUT, and DELETE methods, you can use the CURL tool on UNIX-based systems. If you are using Windows, you can use CURL for Windows. Remember: if you set the HTTP Accept header toapplication/json, the same code will respond in JSON format.

    The sample project in this article has no pagination, security, or other advanced features, but if you want more complete code, you can check out the Footprint Service from the Subversion repository and then compile it through Maven as shown below. When svn asks for a password, just pressENTER.

    svn checkout https://footprint.dev.java.net/svn/footprint/trunk footprint --username guest
    cd footprint
    mvn clean install

    You will find the packed EAR file in the target folder. Questions about the service design and how to install it can be posted directly to the Footprint project's dev mailing list.

    Conclusion and Next Steps

    JAXB and JPA can be combined to reduce the boilerplate code of Java EE applications and also to optimize the performance of RESTful web services--a flexible solution, which preserves the original domain model while following the JPA, JAXB, and HTTP standards. Preliminary tests proved that this solution surpasses the performance of traditional techniques based on adapters; nevertheless, our job is not yet complete. Exposing the full domain model through a web service interface is not realistic when you consider production environments. In the second part of this series, I will demonstrate how to control the exposure of the domain model in different service paths, allowing fine-grained management of which parts of the entity beans will be exposed to which group of the application users, providing insight into how to produce robust and scalable RESTful web services based on Java EE technologies.


    Several people contributed ideas included in this article: the Footprint project members, friends, and anonymous tips in diverse mailing lists, especially the Jerseyand Glassfishmailing lists. I also would like to register special thanks to Roland Huecking and Rudolf Fluetsch for inspirational discussions about Java EE technologies.