Jump to: navigation, search

Difference between revisions of "EclipseLink/UserGuide/JPA/Advanced JPA Development/JPA RESTful Service"

m
m
 
(17 intermediate revisions by one other user not shown)
Line 1: Line 1:
 +
----
 +
 +
 +
'''[[Image:Elug_draft_icon.png|Warning]] This page is now obsolete. '''
 +
 +
For current information, please see "Exposing JPA Entities Through RESTful Services Using EclipseLink Data Services" in the ''EclipseLink Solutions Guide'':
 +
http://www.eclipse.org/eclipselink/documentation/latest/solutions/restful_jpa.htm
 +
 +
 +
----
 +
 +
 +
 +
 
{{EclipseLink_UserGuide
 
{{EclipseLink_UserGuide
 
|info=y
 
|info=y
Line 4: Line 18:
 
|eclipselink=y
 
|eclipselink=y
 
|eclipselinktype=JPA
 
|eclipselinktype=JPA
 +
|api=y
 +
|apis=[http://www.eclipse.org/eclipselink/api/latest/org.eclipse.persistence.jpa.rest rest]
 
|examples=y
 
|examples=y
|example=*[[EclipseLink/Examples/REST/GettingStarted|RESTful Service Example]]}}
+
|example=*[[EclipseLink/Examples/REST/GettingStarted|RESTful Service Example]]}}  
=Expose JPA Entities Through a RESTful Service=
+
This page is in progress...
+
.
+
  
 +
= Exposing JPA Entities Through RESTful Services =
  
This page describes how to expose JPA entities through a a standards-based (JAX-RS/JAXB/JPA) RESTful service. REST is an acronum for REpresentational State Transfer (REST), which is a design idiom that embraces a stateless client-server architecture in which Web services are viewed as resources which can be identified by their URLs.  
+
<br> This page describes how to expose JPA entities through a standards-based (JAX-RS/JAXB/JPA) RESTful service. REST is an acronym for REpresentational State Transfer, which is a design idiom that embraces a stateless client-server architecture in which Web services are viewed as resources which can be identified by their URLs.  
  
Implement a JPA-based JAX-RS service as follows.  Extend <tt>JPASingleKeyResource</tt> or <tt>JPACompositeKeyResource</tt> depending upon the key type.
+
== Implementing a JPA-Based JAX-RS Service ==
 +
 
 +
To implement a JAX-RS service, extend <tt>JPASingleKeyResource</tt> or <tt>JPACompositeKeyResource</tt> depending upon the key type. The following example extends <tt>JPASingleKeyResource</tt>:
  
 
<source lang="java">
 
<source lang="java">
Line 43: Line 59:
  
 
}
 
}
</source>
+
</source>
 +
 
 +
<br>  
  
== Requirements ==
+
== How URIs Are Constructed ==
  
#Expose JPA EntityManager as RESTful (JAX-RS) service
+
Data in RESTful services are referenced using URIs. The common parts of the example URIs in this section are:  
#Execute CRUD operations
+
#Execute named queries:
+
##read one
+
##read many
+
##update
+
##delete
+
#Accept/Return both XML and JSON mime types
+
#Convert JPA exceptions into appropriate HTTP response codes
+
  
=== URI Representation  ===
+
*<tt><nowiki>http://www.example.com/customer-app/rest</nowiki></tt> - The first part of the URI is based on how the application is deployed.
  
Data in a RESTful service is referenced through URIs. The common parts of the URI for this example are:
+
*<tt>customers</tt> - This part of the path corresponds to the JAX-RS <tt>@Path</tt> annotation on the RESTful service.
  
<tt><nowiki>http://www.example.com/customer-app/rest</nowiki></tt> - The first part of the URI is based on how the application is deployed.
+
Other aspects of URI construction are discussed in the following sections:
  
*customers - This part of the path corresponds to the JAX-RS <tt>@Path</tt> annotation on the RESTful service.
+
*[[#URIs_for_JPA_Entities_with_Unary_Keys|URIs for JPA Entities with Unary Keys]]
 +
*[[#URIs_for_JPA_Entities_with_Composite_Keys|URIs for JPA Entities with Composite Keys]]
 +
*[[#URIs_for_Named_Read_Queries|URIs for Named Read Queries]]
 +
*[[#URIs_for_Named_Update_and_Delete_Queries|URIs for Named Update and Delete Queries]]
  
==== URI for JPA Entities with Unary Key ====
+
=== URIs for JPA Entities with Unary Keys ===
  
If the JPA entity has a single part primary key, then in the corresponding URI the primary key is represented as a path parameter. This is a common RESTful operation.
+
If the JPA entity has a single-part primary key, the primary key is represented as a path parameter in the corresponding URI. This is a common RESTful operation.  
  
 
<source lang="java">
 
<source lang="java">
Line 77: Line 90:
  
 
}
 
}
</source>
+
</source>  
  
URI corresponding to Customer entity with id == 1:
+
The URI corresponding to the Customer entity with <tt>id == 1</tt> is:  
  
<tt><nowiki>http://www.example.com/customer-app/rest/customers/1</nowiki></tt>
+
<tt><nowiki>http://www.example.com/customer-app/rest/customers/1</nowiki></tt>  
  
==== URI for JPA Entities with Composite Keys  ====
+
=== URIs for JPA Entities with Composite Keys  ===
  
A different mechanism is used when locating a resource with composite keys.  The URI leverages the property names from the JPA key class as matrix parameters. The advantage of using matrix paramters is that they may be cached. The same representation is also used if composite keys are represented using an embedded key class.
+
To locate a resource with composite keys, the URI includes the property names from the JPA key class as matrix parameters. The advantage of using matrix parameters is that they may be cached. The same representation is also used if composite keys are represented using an embedded key class.  
  
 
<source lang="java">
 
<source lang="java">
 
@Entity
 
@Entity
@IdClass(CustomerID.clsas)
+
@IdClass(CustomerID.class)
 
public class Customer implements Serializable {
 
public class Customer implements Serializable {
  
Line 99: Line 112:
  
 
}
 
}
</source>
 
  
<source lang="java">
 
 
public class CustomerID {
 
public class CustomerID {
  
Line 125: Line 136:
  
 
}
 
}
</source>
+
</source>  
  
URI corresponding to the instance of Customer with id == 1 and country == CA:  
+
The URI corresponding to the instance of Customer with <tt>id == 1</tt> and <tt>country == CA</tt> is:  
  
<tt><nowiki>http://www.example.com/customer-app/rest/customers;id=1;country=CA</nowiki></tt>
+
<tt><nowiki>http://www.example.com/customer-app/rest/customers;id=1;country=CA</nowiki></tt>  
  
==== Named Queries:  Read ====
+
=== URIs for Named Read Queries  ===
  
A named read query call must be mapped to a URI. Below is an example named read query:
+
A named read query call must be mapped to a URI. Below is an example named read query:  
  
 
<source lang="java">
 
<source lang="java">
Line 141: Line 152:
 
                     "WHERE c.firstName = :firstName AND " +
 
                     "WHERE c.firstName = :firstName AND " +
 
                     "      c.lastName = :lastName")
 
                     "      c.lastName = :lastName")
</source>
+
</source>  
  
Get Single Result:
+
An example of a URI for retrieving a single result is:  
  
<tt><nowiki>http://www.example.com/customer-app/rest/customers/singleResult/findCustomerByName;firstName=Jane;lastName=Doe</nowiki></tt>
+
<tt><nowiki>http://www.example.com/customer-app/rest/customers/singleResult/findCustomerByName;firstName=Jane;lastName=Doe</nowiki></tt>  
  
Get Result List:
+
An example of a URI for retrieving a result list is:  
  
<tt><nowiki>http://www.example.com/customer-app/rest/customers/resultList/findCustomerByName;firstName=Jane;lastName=Doe?firstResult=1&maxResults=10</nowiki></tt>
+
<tt><nowiki>http://www.example.com/customer-app/rest/customers/resultList/findCustomerByName;firstName=Jane;lastName=Doe?firstResult=1&maxResults=10</nowiki></tt>  
  
URI components:
+
The components of the URI in the previous example are:
* <tt>findCustomersByName</tt> - This corresponds to the name of the named query.
+
* <tt>singleResult</tt> or <tt>resultList</tt> - This portion indicates whether one or many results are returned.
+
* <tt>;firstName=Jane;lastName=Doe</tt> - These are matrix parameters; the name of the parameter must match exactly the parameter name in the named query.
+
* <tt>?firstResult=1&maxResults=10</tt> - Optional query parameters to specify <tt>firstResult</tt> and <tt>maxResults</tt>.
+
  
The parameters are used to build the equivalent of the following:
+
*<tt>findCustomersByName</tt> - This corresponds to the name of the named query.
 +
*<tt>singleResult</tt> or <tt>resultList</tt> - This portion indicates whether one or many results are returned.
 +
*<tt>;firstName=Jane;lastName=Doe</tt> - These are matrix parameters. The name of the parameter must match exactly the parameter name in the named query.
 +
*<tt>?firstResult=1&amp;maxResults=10</tt> - These are optional query parameters to specify <tt>firstResult</tt> and <tt>maxResults</tt>.
 +
 
 +
The parameters are used to build the equivalent of the following:  
  
 
<source lang="java">
 
<source lang="java">
Line 166: Line 178:
 
query.setMaxResults(10);
 
query.setMaxResults(10);
 
return query.getResultList();
 
return query.getResultList();
</source>
+
</source>  
  
==== Named Queries:  Update & Delete ====
+
=== URIs for Named Update and Delete Queries  ===
  
A named update and delete query calls must be mapped to a URI. Below is an example named update query:
+
A named update and delete query call must be mapped to a URI. Below is an example named update query:  
  
 
<source lang="java">
 
<source lang="java">
Line 177: Line 189:
 
                     "SET c.address.city = :newCity " +
 
                     "SET c.address.city = :newCity " +
 
                     "WHERE c.address.city = :oldCity")  
 
                     "WHERE c.address.city = :oldCity")  
</source>
+
</source>  
  
Execute the query:
+
The URL for executing that query is:  
  
<tt><nowiki>http://www.example.com/customer-app/rest/customers/execute/updateCustomersByCity;oldCity=Nepean;newCity=Ottawa</nowiki></tt>
+
<tt><nowiki>http://www.example.com/customer-app/rest/customers/execute/updateCustomersByCity;oldCity=Nepean;newCity=Ottawa</nowiki></tt>  
  
URI components:
+
The components of the URI in the previous example are:
* <tt>updateCustomersByCity</tt> - This corresponds to the name of the named query.
+
* <tt>execute</tt> - This portion indicates the query will be executed.
+
* <tt>;oldCity=Nepean;newCity=Ottawa</tt> - These are matrix parameters; the name of the parameter must match exactly the parameter name in the named query.
+
  
The parameters are to build the equivalent of the following:
+
*<tt>updateCustomersByCity</tt> - This corresponds to the name of the named query.
 +
*<tt>execute</tt> - This portion indicates the query will be executed.
 +
*<tt>;oldCity=Nepean;newCity=Ottawa</tt> - These are matrix parameters; the name of the parameter must match exactly the parameter name in the named query.
 +
 
 +
The parameters are used to build the equivalent of the following:  
  
 
<source lang="java">
 
<source lang="java">
Line 195: Line 208:
 
query.setParameter("newCity", "Ottawa");
 
query.setParameter("newCity", "Ottawa");
 
query.executeUpdate();
 
query.executeUpdate();
</source>
+
</source>  
 +
 
 +
== Using Create, Read, Update, and Delete (CRUD) Operations on RESTful Services  ==
 +
 
 +
The CRUD operations are described in the following sections:
 +
 
 +
*[[#POST_-_Create_Operation|POST - Create Operation]]
 +
*[[#GET_-_Read_Operation|GET - Read Operation]]
 +
*[[#PUT_-_Update_Operation|PUT - Update Operation]]
 +
*[[#DELETE_-_Delete_Operation|DELETE - Delete Operation]]
  
=== REST (CRUD) Operations  ===
+
The examples in these sections use the Jersey client APIs. Jersey is the open source JAX-RS (JSR 311) Reference Implementation for building RESTful Web services. (For more information about Jersey, see http://jersey.java.net/.)  
  
==== POST - Create Operation  ====
+
=== POST - Create Operation  ===
  
Using the Jersery client APIs, the following is how a post operation is called on the EclipseLink service. The XML message will converted to the appropriate object type using JAXB.
+
The following example shows a post operation called on a service, using the Jersery client APIs. The XML message is converted to the appropriate object type using JAXB.  
  
 
<source lang="java">
 
<source lang="java">
Line 208: Line 230:
 
ClientResponse response = resource.type("application/xml").post(ClientResponse.class, "<customer>...</customer>");
 
ClientResponse response = resource.type("application/xml").post(ClientResponse.class, "<customer>...</customer>");
 
System.out.println(response);
 
System.out.println(response);
</source>
+
</source>  
  
This call will be received by
+
This call will be received by the following:
  
 
<source lang="java">
 
<source lang="java">
Line 220: Line 242:
 
     return Response.created(uriBuilder.build()).build();
 
     return Response.created(uriBuilder.build()).build();
 
}
 
}
</source>
+
</source>  
  
Successful Responses
+
Examples of successful responses to this call are:
* 200 OK
+
* Return the URI (the representation discussed earlier) for the created entity.
+
  
Error Responses:
+
*<tt>200 OK</tt>
* ?
+
*The URI (as described earlier) for the created entity is returned.
  
==== GET - Read Operation  ====
+
Examples of error responses are:
  
Get is a read-only operation. It is used to query resources. The following is an example of how to invoke a GET call using the Jersey client APIs:
+
*&nbsp;? ''(The spec only has this question mark.)''
 +
 
 +
=== GET - Read Operation  ===
 +
 
 +
Get is a read-only operation. It is used to query resources. The following is an example of how to invoke a GET call using the Jersey client APIs:  
  
 
<source lang="java">
 
<source lang="java">
 
WebResource resource = client.resource("http://www.example.com/customer-app/rest/customers;id=1;country=CA");
 
WebResource resource = client.resource("http://www.example.com/customer-app/rest/customers;id=1;country=CA");
 
ClientResponse response = resource.accept(mimeType).get(ClientResponse.class);
 
ClientResponse response = resource.accept(mimeType).get(ClientResponse.class);
</source>
+
</source>  
  
We will need to differentiate between the single key case that uses path parameters and the composite key case that uses matrix parameters:
+
Single key cases that use path parameters and composite key cases that use matrix parameters are handled differently, as shown below:  
  
'''Single Key - Path Parameter'''
+
'''Single Key - Path Parameter'''  
 
+
The unary key parameter will be passed directly to us.  Note the String to KeyType conversion will be done using JAXB conversion rules and not JPA conversion rules.  There should be no differences for common key types such as Strings and numeric types.
+
  
 
<source lang="java">
 
<source lang="java">
Line 251: Line 273:
 
     return entityManager().find(entityClass, id);
 
     return entityManager().find(entityClass, id);
 
}
 
}
</source>
+
</source>  
  
'''Composite Key - Matrix Parameters'''
+
'''Composite Key - Matrix Parameters'''  
 
+
An instance of the primary key class will need to be derived from the matrix parameters.  A utility will need to be provided for this.
+
  
 
<source lang="java">
 
<source lang="java">
Line 263: Line 283:
 
     return entityManager().find(entityClass, getPrimaryKey(info));
 
     return entityManager().find(entityClass, getPrimaryKey(info));
 
}
 
}
</source>
+
</source>  
 +
 
 +
Examples of successful responses to this call are:
 +
 
 +
*<tt>200 OK</tt> - If a result is returned
 +
*<tt>204 No Content</tt> - If no results are returned
  
Successful Responses
+
Examples of error responses are:
* 200 OK - If a result is returned
+
* 204 No Content - If no results are returned
+
  
Error Responses:
+
*&nbsp;? ''(The spec only has this question mark.)''
* ?
+
  
==== PUT - Update Operation  ====
+
=== PUT - Update Operation  ===
  
 
The put operation updates the underlying resource. When using put the client knows the identity of the resource being updated. The following is an example of how to invoke a PUT call using the Jersey client APIs:  
 
The put operation updates the underlying resource. When using put the client knows the identity of the resource being updated. The following is an example of how to invoke a PUT call using the Jersey client APIs:  
Line 281: Line 303:
 
ClientResponse response = resource.type("application/xml").put(ClientResponse.class, "<customer>...</customer>");
 
ClientResponse response = resource.type("application/xml").put(ClientResponse.class, "<customer>...</customer>");
 
System.out.println(response);
 
System.out.println(response);
</source>
+
</source>  
  
 
This call will be received by  
 
This call will be received by  
Line 291: Line 313:
 
     entityManager().merge(entity);
 
     entityManager().merge(entity);
 
}
 
}
</source>
+
</source>  
  
Successful Responses
+
An example of a successful response is:
* 200 OK
+
  
Error Responses:
+
* <tt>200 OK</tt>
* 409 Conflict - Locking related exception
+
  
==== DELETE - Delete Operation  ====
+
An example of an error response is:
  
The delete operation is used to remove resources. It is not an error to remove a non-existent resource. Below is an example using the Jersey client APIs:
+
* <tt>409 Conflict</tt> - Locking related exception
 +
 
 +
=== DELETE - Delete Operation  ===
 +
 
 +
The delete operation is used to remove resources. It is not an error to remove a non-existent resource. Below is an example using the Jersey client APIs:  
  
 
<source lang="java">
 
<source lang="java">
 
WebResource resource = client.resource("http://www.example.com/customer-app/rest/customers/1");
 
WebResource resource = client.resource("http://www.example.com/customer-app/rest/customers/1");
 
ClientResponse response = resource.delete(ClientResponse.class);
 
ClientResponse response = resource.delete(ClientResponse.class);
</source>
+
</source>  
  
We will need to differentiate between the single key case that uses path parameters and the composite key case that uses matrix parameters:  
+
Single key cases that use path parameters and composite key cases that use matrix parameters are handled differently, as shown below:  
  
'''Single Key - Path Parameter'''
+
'''Single Key - Path Parameter'''  
  
 
<source lang="java">
 
<source lang="java">
Line 318: Line 342:
 
     super.delete(id);
 
     super.delete(id);
 
}
 
}
</source>
+
</source>  
  
'''Composite Key - Matrix Parameters'''
+
'''Composite Key - Matrix Parameters'''  
 
+
An instance of the primary key class will need to be derived from the matrix parameters. A utility will need to be provided for this.
+
  
 
<source lang="java">
 
<source lang="java">
Line 329: Line 351:
 
     super.delete(getPrimaryKey(info));
 
     super.delete(getPrimaryKey(info));
 
}
 
}
</source>
+
</source>
 +
 
 +
An example of a successful response is:
 +
 
 +
* <tt>200 OK</tt>
  
Successful Responses
+
An example of an error response is:
* 200 OK
+
  
Error Responses:
+
*&nbsp;? ''(The spec only has this question mark.)''
*
+
  
=== Matrix Parameters to Instance of ID Class ===
+
== Matrix Parameters to Instance of ID Class ==
  
The matrix parameters could be converted to an ID class in the following manner (Note the code below is currently using query paramters and needs to be updated):
+
You can convert matrix parameters to an ID class, as shown below:
 +
''(From spec: "(Note the code below is currently using query parameters and needs to be updated):")''
  
 
<source lang="java">
 
<source lang="java">
Line 355: Line 380:
 
     }
 
     }
 
}
 
}
</source>
+
</source>  
  
The key class can be obtained using the the JPA metamodel facility:
+
Obtain the key class using the the JPA metamodel facility:  
  
 
<source lang="java">
 
<source lang="java">
 
keyClass = (Class<KeyType>) entityManager().getMetamodel().entity(entityClass).getIdType().getJavaType();
 
keyClass = (Class<KeyType>) entityManager().getMetamodel().entity(entityClass).getIdType().getJavaType();
</source>
+
</source>  
 
+
  
 +
<br>
  
 +
<!--
 
== API  ==
 
== API  ==
  
Much of the shared behavior is available in the super class:
+
Much of the shared behavior is available in the super class:  
  
 
<source lang="java">
 
<source lang="java">
Line 418: Line 444:
  
 
}
 
}
</source>
+
</source>  
  
A specialized class will be available for a service based on a single key entity:
+
A specialized class is available for a service based on a single key entity:  
  
 
<source lang="java">
 
<source lang="java">
Line 458: Line 484:
  
 
}
 
}
</source>
+
</source>  
  
Another specialized class will be available for a service based on a composite key entity:
+
Another specialized class is available for a service based on a composite key entity:  
  
 
<source lang="java">
 
<source lang="java">
Line 501: Line 527:
 
     }
 
     }
  
}</source>
+
}</source>  
 
+
== Config files  ==
+
 
+
No extra configuration files are required.  However, you are responsible for providing the required JAX-RS, JPA, and JAXB configuration files.
+
 
+
=== JAX-RS ===
+
* You must create the JAX-RS deployment artifacts appropriate to your deployment platform.
+
  
=== JPA ===
+
-->
  
* You must create the necessary artifacts for JPA.
+
== Configuration Files  ==
  
=== JAXB ===
+
No extra configuration files are required for RESTful services. However, you are responsible for providing the required JAX-RS, JPA, and JAXB configuration files:
  
* You must create the necessary artifacts for JAXB
+
*JAX-RS - You must create the JAX-RS deployment artifacts appropriate to your deployment platform.
** jaxb.properties file to specify JAXB implementation
+
** eclipselink-oxm.xml as an alternate metadata representation
+
  
 +
*JPA - You must create the necessary artifacts for JPA.
  
 +
*JAXB - You must create the necessary artifacts for JAXB:
 +
**<tt>jaxb.properties</tt> file to specify JAXB implementation
 +
**<tt>eclipselink-oxm.xml</tt> as an alternate metadata representation
  
 +
<br>
  
 +
<br>
  
 
{{EclipseLink_JPA
 
{{EclipseLink_JPA

Latest revision as of 07:34, 17 April 2013



Warning This page is now obsolete.

For current information, please see "Exposing JPA Entities Through RESTful Services Using EclipseLink Data Services" in the EclipseLink Solutions Guide: http://www.eclipse.org/eclipselink/documentation/latest/solutions/restful_jpa.htm





EclipseLink JPA

link="http://wiki.eclipse.org/EclipseLink"
EclipseLink
Website
Download
Community
Mailing ListForumsIRC
Bugzilla
Open
Help Wanted
Bug Day
Contribute
Browse Source

Elug api package icon.png Key API rest


Exposing JPA Entities Through RESTful Services


This page describes how to expose JPA entities through a standards-based (JAX-RS/JAXB/JPA) RESTful service. REST is an acronym for REpresentational State Transfer, which is a design idiom that embraces a stateless client-server architecture in which Web services are viewed as resources which can be identified by their URLs.

Implementing a JPA-Based JAX-RS Service

To implement a JAX-RS service, extend JPASingleKeyResource or JPACompositeKeyResource depending upon the key type. The following example extends JPASingleKeyResource:

import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
import javax.ws.rs.Path;
 
import org.eclipse.persistence.jpa.rest.JPASingleKeyResource;
 
@Stateless
@LocalBean
@Path("/customers")
public class CustomerService extends JPASingleKeyResource<Customer, Long> {
 
    @PersistenceContext(unitName="CustomerService", type=PersistenceContextType.TRANSACTION)
    EntityManager entityManager;
 
    public CustomerService() {
        super(Customer.class);
    }
 
    @Override
    protected EntityManager entityManager() {
        return entityManager;
    }
 
}


How URIs Are Constructed

Data in RESTful services are referenced using URIs. The common parts of the example URIs in this section are:

  • http://www.example.com/customer-app/rest - The first part of the URI is based on how the application is deployed.
  • customers - This part of the path corresponds to the JAX-RS @Path annotation on the RESTful service.

Other aspects of URI construction are discussed in the following sections:

URIs for JPA Entities with Unary Keys

If the JPA entity has a single-part primary key, the primary key is represented as a path parameter in the corresponding URI. This is a common RESTful operation.

@Entity
public class Customer implements Serializable {
 
    @Id
    private long id;
 
}

The URI corresponding to the Customer entity with id == 1 is:

http://www.example.com/customer-app/rest/customers/1

URIs for JPA Entities with Composite Keys

To locate a resource with composite keys, the URI includes the property names from the JPA key class as matrix parameters. The advantage of using matrix parameters is that they may be cached. The same representation is also used if composite keys are represented using an embedded key class.

@Entity
@IdClass(CustomerID.class)
public class Customer implements Serializable {
 
    @Id
    private long id;
 
    @Id
    private String country;
 
}
 
public class CustomerID {
 
    private String country;
    private long id;
 
    public CustomerID() {
        super();
    }
 
    public CustomerID(String country, long id) {
        this.country = country;
        this.id = id;
    }
 
    public String getCountry() {
        return country;
    }
 
    public long getId() {
        return id;
    }
 
}

The URI corresponding to the instance of Customer with id == 1 and country == CA is:

http://www.example.com/customer-app/rest/customers;id=1;country=CA

URIs for Named Read Queries

A named read query call must be mapped to a URI. Below is an example named read query:

@NamedQuery(name = "findCustomerByName",
            query = "SELECT c " +
                    "FROM Customer c " +
                    "WHERE c.firstName = :firstName AND " +
                    "      c.lastName = :lastName")

An example of a URI for retrieving a single result is:

http://www.example.com/customer-app/rest/customers/singleResult/findCustomerByName;firstName=Jane;lastName=Doe

An example of a URI for retrieving a result list is:

http://www.example.com/customer-app/rest/customers/resultList/findCustomerByName;firstName=Jane;lastName=Doe?firstResult=1&maxResults=10

The components of the URI in the previous example are:

  • findCustomersByName - This corresponds to the name of the named query.
  • singleResult or resultList - This portion indicates whether one or many results are returned.
  • ;firstName=Jane;lastName=Doe - These are matrix parameters. The name of the parameter must match exactly the parameter name in the named query.
  • ?firstResult=1&maxResults=10 - These are optional query parameters to specify firstResult and maxResults.

The parameters are used to build the equivalent of the following:

Query query = entityManager.createNamedQuery("findCustomersByCity");
query.setParameter("firstName", "Jane");
query.setParameter("lastName", "Doe");
query.setFirstResult(1);
query.setMaxResults(10);
return query.getResultList();

URIs for Named Update and Delete Queries

A named update and delete query call must be mapped to a URI. Below is an example named update query:

@NamedQuery(name = "updateCustomersByCity",
            query = "UPDATE Customer c " +
                    "SET c.address.city = :newCity " +
                    "WHERE c.address.city = :oldCity")

The URL for executing that query is:

http://www.example.com/customer-app/rest/customers/execute/updateCustomersByCity;oldCity=Nepean;newCity=Ottawa

The components of the URI in the previous example are:

  • updateCustomersByCity - This corresponds to the name of the named query.
  • execute - This portion indicates the query will be executed.
  • ;oldCity=Nepean;newCity=Ottawa - These are matrix parameters; the name of the parameter must match exactly the parameter name in the named query.

The parameters are used to build the equivalent of the following:

Query query = entityManager.createNamedQuery("updateCustomersByCity");
query.setParameter("oldCity", "Nepean");
query.setParameter("newCity", "Ottawa");
query.executeUpdate();

Using Create, Read, Update, and Delete (CRUD) Operations on RESTful Services

The CRUD operations are described in the following sections:

The examples in these sections use the Jersey client APIs. Jersey is the open source JAX-RS (JSR 311) Reference Implementation for building RESTful Web services. (For more information about Jersey, see http://jersey.java.net/.)

POST - Create Operation

The following example shows a post operation called on a service, using the Jersery client APIs. The XML message is converted to the appropriate object type using JAXB.

Client c = Client.create();
WebResource resource = client.resource("http://www.example.com/customer-app/rest/customers");
ClientResponse response = resource.type("application/xml").post(ClientResponse.class, "<customer>...</customer>");
System.out.println(response);

This call will be received by the following:

@POST
@Consumes({"application/xml", "application/json"})
public Response create(@Context UriInfo uriInfo, EntityType entity) {
    entityManager().persist(entity);
    UriBuilder uriBuilder = pkUriBuilder(uriInfo.getAbsolutePathBuilder(), entity);
    return Response.created(uriBuilder.build()).build();
}

Examples of successful responses to this call are:

  • 200 OK
  • The URI (as described earlier) for the created entity is returned.

Examples of error responses are:

  •  ? (The spec only has this question mark.)

GET - Read Operation

Get is a read-only operation. It is used to query resources. The following is an example of how to invoke a GET call using the Jersey client APIs:

WebResource resource = client.resource("http://www.example.com/customer-app/rest/customers;id=1;country=CA");
ClientResponse response = resource.accept(mimeType).get(ClientResponse.class);

Single key cases that use path parameters and composite key cases that use matrix parameters are handled differently, as shown below:

Single Key - Path Parameter

@GET
@Path("{id}")
@Produces({"application/xml", "application/json"})
public EntityType read(@PathParam("id") KeyType id) {
    return entityManager().find(entityClass, id);
}

Composite Key - Matrix Parameters

@GET
@Produces({"application/xml", "application/json"})
public EntityType read(@Context UriInfo info) {
    return entityManager().find(entityClass, getPrimaryKey(info));
}

Examples of successful responses to this call are:

  • 200 OK - If a result is returned
  • 204 No Content - If no results are returned

Examples of error responses are:

  •  ? (The spec only has this question mark.)

PUT - Update Operation

The put operation updates the underlying resource. When using put the client knows the identity of the resource being updated. The following is an example of how to invoke a PUT call using the Jersey client APIs:

Client c = Client.create();
WebResource resource = client.resource("http://www.example.com/customer-app/rest/customers/1");
ClientResponse response = resource.type("application/xml").put(ClientResponse.class, "<customer>...</customer>");
System.out.println(response);

This call will be received by

@PUT
@Consumes({"application/xml", "application/json"})
public void update(EntityType entity) {
    entityManager().merge(entity);
}

An example of a successful response is:

  • 200 OK

An example of an error response is:

  • 409 Conflict - Locking related exception

DELETE - Delete Operation

The delete operation is used to remove resources. It is not an error to remove a non-existent resource. Below is an example using the Jersey client APIs:

WebResource resource = client.resource("http://www.example.com/customer-app/rest/customers/1");
ClientResponse response = resource.delete(ClientResponse.class);

Single key cases that use path parameters and composite key cases that use matrix parameters are handled differently, as shown below:

Single Key - Path Parameter

@DELETE
@Path("{id}")
public void delete(@PathParam("id") KeyType id) {
    super.delete(id);
}

Composite Key - Matrix Parameters

@DELETE
public void delete(@Context UriInfo info) {
    super.delete(getPrimaryKey(info));
}

An example of a successful response is:

  • 200 OK

An example of an error response is:

  •  ? (The spec only has this question mark.)

Matrix Parameters to Instance of ID Class

You can convert matrix parameters to an ID class, as shown below: (From spec: "(Note the code below is currently using query parameters and needs to be updated):")

private KeyType getPrimaryKey(UriInfo info) {
    try {
        KeyType pk = (KeyType) PrivilegedAccessHelper.newInstanceFromClass(keyClass);
        for(Entry<String, List<String>> entry : info.getQueryParameters().entrySet()) {
            Field pkField = PrivilegedAccessHelper.getField(keyClass, entry.getKey(), true);
            Object pkValue = ConversionManager.getDefaultManager().convertObject(entry.getValue().get(0), pkField.getType());
            PrivilegedAccessHelper.setValueInField(pkField, pk, pkValue);
        }
        return pk;
    } catch(Exception e) {
        throw new RuntimeException(e);
    }
}

Obtain the key class using the the JPA metamodel facility:

keyClass = (Class<KeyType>) entityManager().getMetamodel().entity(entityClass).getIdType().getJavaType();



Configuration Files

No extra configuration files are required for RESTful services. However, you are responsible for providing the required JAX-RS, JPA, and JAXB configuration files:

  • JAX-RS - You must create the JAX-RS deployment artifacts appropriate to your deployment platform.
  • JPA - You must create the necessary artifacts for JPA.
  • JAXB - You must create the necessary artifacts for JAXB:
    • jaxb.properties file to specify JAXB implementation
    • eclipselink-oxm.xml as an alternate metadata representation



Eclipselink-logo.gif
Version: 2.2.0 DRAFT
Other versions...