EclipseLink is an open source ORM framework developed by the Eclipse Foundation. At the end of the year, the release of version 2.6.0 is planned. project. In anticipation of this, I want to introduce you to some of the new features of the JPA-RS service, which is part of EclipseLink.
JPA-RS allows you to automatically generate RESTful services based on the model provided by the user JPA. At the same time, practically no additional work is required from the user.
Service version in URL
From version to version it is possible to change the semantics of the data transfer protocol. JSON-scheme of resources in version 2.0 of the service is different from the JSON-scheme used in the previous version. For compatibility, JPA-RS can return data using old formats. For this version of the protocol rendered in the URL.
The base URL looks like this:
http(s)://{server:port}/{app}/persistence/{version}/{persistent-unit}/...
Where:
- server: port - server address and port.
- app - the name of your application (context root).
- persistence - The entry point to the JPA-RS application. Constant.
- version - Optional. JPA-RS version. Currently, the supported values ​​are “v1.0” (previous version), “v2.0” (new version) and “latest” (latest version).
- persistent-unit - The name of the persistent unit as specified in persistence.xml.
The service version may be skipped, in this case the value “v1.0” is used.
')
Examples:
A request for a Car object with a primary key of 1 from the persistent car-pu unit using protocol semantics version 1.0:
http(s)://localhost:8080/jpars-test/persistence/car-pu/entity/Car/1
Same:
http(s)://localhost:8080/jpars-test/persistence/v1.0/car-pu/entity/Car/1
Request the same data, but using the semantics of service version 2.0:
http(s)://localhost:8080/jpars-test/persistence/v2.0/car-pu/entity/Car/1
Since the latest version is currently 2.0, the following query will return the same as the previous one:
http(s)://localhost:8080/jpars-test/persistence/latest/car-pu/entity/Car/1
Further, solely for readability, I will designate
http (s): // localhost: 8080 / jpars-test / persistence / v2.0 as
{root} .
Paginated output
JPARS allows you to paginate long lists and return only the page selected by the user. This works for queries (Named Query) and for fields of type Collection.
Paging is the only JPA-RS function that requires configuration. This is done using annotations.
Consider the following example:
@Entity @Table(name = "CAR") @NamedQueries({ @NamedQuery( name = "Car.findAll", query = "SELECT c FROM Car c ORDER BY c.name"), @NamedQuery( name = "Car.findAllPageable", query = "SELECT c FROM Car c ORDER BY c.name"), }) @RestPageableQueries({ @RestPageableQuery(queryName = "Car.findAllPageable", limit = 20) }) public class Car { @Id @Column(name = "CAR_ID") private Integer id; @Column(name = "CAR_NAME") private String name; @Column(name = "CAR_SHORT_DESCR") private String shortDescr; @Column(name = "CAR_LONG_DESCR") private String longDescr;
This is the standard entity class with two JPARS annotations.
@RestPageableQueries({ @RestPageableQuery(queryName = "Car.findAllPageable", limit = 20) })
This piece of code says that the
Car.findAllPageable request should be issued through a RESTful service page by page with a page size of 20 entries.
To configure paginal output, the call uses two parameters:
- limit - page size. Cannot be higher than the limit value specified in the @RestPageableQuery annotation. It is also the default.
- offset - offset from the beginning of the list. The sequence number of the first entry returned. The default value is 0.
For example, the following queries are similar:
GET <root>/query/Car.findAllPageable GET <root>/query/Car.findAllPageable?limit=20&offset=0
and return the following JSON:
{ "items": [ { "id": 1, "name": "Mazda MX-5", ... }, ... < 19 > ... ], "hasMore": true, "limit": 20, "offset": 0, "count": 20, "links": [ { "rel": "self", "href": "{root}/query/Car.findAllPageable" } { "rel": "canonical", "href": "{root}/query/Car.findAllPageable" } { "rel": "next", "href": "{root}/query/Car.findAllPageable?offset=20" } ] }
The server response also contains additional information:
- hasMore - true if this page is not the last.
- limit - the page size used by the server.
- offset is the offset used.
- count - the number of entries on the page.
- link next - URL of the next page (if available)
- link prev - the URL of the previous page (if available)
Second page:
{root}/query/Car.findAllPageable?offset=20
or
{root]/query/Car.findAllPageable?limit=20&offset=20
The third page of 10 entries:
{root}/query/Car.findAllPageable?limit=10&offset=20
7 entries since the third:
{root}/query/Car.findAllPageable?limit=7&offset=3
The server always uses the minimum limit specified in the request and used in the annotation. I.e
{root}/query/Car.findAllPageable?limit=100
returns only 20 entries. The limit value in the server response will be 20, as in the example above.
Filtering fields
When requesting data, sometimes it is necessary to return not the entire record, but only some fields. For example, the Car class longDescr field contains an impressively sized text that we do not want to transmit over the network. For this is the filtering of fields.
Filtering is configured by two parameters:
- fields - the list of fields returned by the server. Fields are separated by commas.
- excludeFields - a list of fields that are not returned by the server.
For example:
GET {root}/entity/Car/1?fields=id,name,shortDescr
Return only the
id ,
name and
shortDescr fields of the Car class:
{ "id": 1, "name": "Mazda MX-5", "shortDescr": " ", ... }
The same query will return the same:
GET {root}/entity/Car/1?excludeFields=longDescr
If you try to use both the fields and excludeFields parameters in one request, the server will return an error.
Metadata
Metadata contains additional information about the resource. In our case, this is a link to the JSON resource scheme and the base URL.
For example, the metadata for our Car class look like this:
{ "name": "Car", "links": [ { "rel": "alternate", "href": "<root>/metadata-catalog/entity/Car", "mediaType": "application/schema+json" }, { "rel": "canonical", "href": "<root>/metadata-catalog/entity/Car", "mediaType": "application/json" }, { "rel": "describes", "href": "{root}/entity/Car" } ] }
You can get metadata for the Car class like this:
{root}/metadata-catalog/entity/Car
For the Car.findAll query like this:
{root}/metadata-catalog/query/Car.findAll
Another way to get metadata is to call the OPTIONS method on the base URL of the resource.
OPTIONS <root>/entity/Basket
The server will return the link to the metadata in the Link header c rel = "describedby"
Link: <root/metadata-catalog/entity/Basket>; rel="describedby"
Resource catalog
The resource catalog, like the book's table of contents, contains metadata for all available resources. This is the right place to start working with an unfamiliar service. Here you can always see the available objects and requests.
The resource catalog is available at the following address:
GET <root>/metadata-catalog
Server response:
{ "items": [ { "name": "Car", ... }, { "name": "Car.findAll", ... }, { "name": "Car.findAllPageable", ... } ], "links": [ { "rel": "canonical", "href": "<root>/metadata-catalog" } ] }
I trimmed the server response solely for readability. Metadata for all resources also looks as indicated at the beginning of the chapter.
JSON resource schema
Although the
JSON schema is not yet an approved standard and the work on the specification has not yet been completed, the JPS-RS already partially supports draft 4 specifications. This concerns the output format of objects and the list of objects.
The resource metadata URL can also be used to get its (resource) JSON schema. To do this, perform an HTTP GET request using the media type “application / schema + json”. That is, by setting the value of “application / schema + json” in the HTTP header “accept”.
Getting the schema for the Car class:
GET <root>/metadata-catalog/entity/Car HTTP/1.1 Accept-Encoding: gzip,deflate accept: application/schema+json Host: <host:port> Proxy-Connection: Keep-Alive User-Agent: Apache-HttpClient/4.1.1 (java 1.5)
Server response:
{ "$schema": "<root>/metadata-catalog/entity/Car#", "allOf": [ { "$ref": "rest-schemas/#/singularResource" } ], "title": "Car", "properties": { "id": { "type": "number" }, "name": { "type": "string" }, "shortDescr": { "type": "string" }, "longDescr": { "type": "string" }, }, "links": [ { "rel": "describedby", "href": "<root>/entity/Car" }, { "rel": "find", "href": "{root}/entity/Car/{primaryKey}", "method": "GET" }, { "rel": "create", "href": "{root}/entity/Car", "method": "PUT" }, { "rel": "update", "href": "{root}/entity/Car", "method": "POST" }, { "rel": "delete", "href": "{root}/entity/Car/{primaryKey}", "method": "DELETE" } ] }
That's all. Hope you enjoyed the review.
Nightly builds EclipseLink can be downloaded here:
www.eclipse.org/eclipselink/downloads/nightly.php