Краткий обзор новых возможностей JPA-RS в EclipseLink

EclipseLink — это ORM фрэймворк с открытым исходным кодом, разрабатываемый Eclipse Foundation. В конце года запланирован выход версии 2.6.0. проекта. В преддверии этого, я хочу ознакомить вас с некоторыми новыми возможностями службы JPA-RS, которая является частью EclipseLink.JPA-RS позволяет автоматически генерировать RESTful сервисы на базе предоставленной пользователем JPA модели. При этом практически никакой дополнительной работы от пользователя не требуется.Версия сервиса в URLОт версии к версии возможно изменение семантики протокола передачи данных. JSON-cхема ресурсов в версии 2.0 сервиса отличается от JSON-схемы, используемой в предыдущей версии. Для обеспечения совместимости JPA-RS умеет возвращать данные используя старые форматы. Для этого версия протокола вынесена в URL.Базовый URL выглядит так:

http (s)://{server: port}/{app}/persistence/{version}/{persistent-unit}/… Где: server: port — адрес и порт сервера. app — имя вашего приложения (context root). persistence — Точка входа в JPA-RS приложение. Константа. version — Не обязательный. Версия JPA-RS. На данный момент поддерживаются значения «v1.0» (предыдущая версия), «v2.0» (новая версия) и «latest» (последняя версия). persistent-unit — Имя persistent unit как указано в persistence.xml. Версия сервиса может быть пропущена, в этом случае используется значение «v1.0».Примеры:

Запрос объекта Car с примарным ключом 1 из персистент юнита car-pu используя семантику протокола версии 1.0:

http (s)://localhost:8080/jpars-test/persistence/car-pu/entity/Car/1 Тоже самое: http (s)://localhost:8080/jpars-test/persistence/v1.0/car-pu/entity/Car/1 Запрос тех же данных, но используя семантику сервиса версии 2.0: http (s)://localhost:8080/jpars-test/persistence/v2.0/car-pu/entity/Car/1 Так как последняя версия на данный момент 2.0, то следующий запрос вернет тоже самое, что и предыдущий: http (s)://localhost:8080/jpars-test/persistence/latest/car-pu/entity/Car/1 Далее, исключительно для читабельности, я обозначу http (s)://localhost:8080/jpars-test/persistence/v2.0 как {root}.Постраничный вывод JPARS позволяет разделять на страницы длинные списки и возвращать только выбранную пользователем страницу. Это работает для запросов (Named Query) и для полей типа Collection.Постраничный вывод — это единственная функция JPA-RS, требующая конфигурации. Это делается с помощью аннотаций.Рассмотрим следующий пример:

@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; // Getters and setters are skipped } Это стандартный entity класс c двумя JPARS аннотациями.

@RestPageableQueries ({ @RestPageableQuery (queryName = «Car.findAllPageable», limit = 20) }) Этот кусок кода говорит, что запрос Car.findAllPageable должен выдаваться через RESTful сервис постранично с размером страницы — 20 записей.Для конфигурации постраничного вывода при вызове используются два параметра: limit — размер страницы. Не может быть выше значения limit указанного в аннотации @RestPageableQuery. Оно же является значением по умолчанию. offset — смещение от начала списка. Порядковый номер первой возвращаемой записи. Значение по умолчению — 0. К примеру, следующие запросы аналогичны: GET /query/Car.findAllPageable GET /query/Car.findAllPageable? limit=20&offset=0 и вернут следующий 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» } ] } Ответ сервера также содержит дополнительную информацию: hasMore — true если данная страница не является последней. limit — размер страницы используемый сервером. offset — используемое смещение. count — количество записей на странице. ссылка next — URL следующей страницы (если доступна) ссылка prev — URL предыдущей страницы (если доступна) Вторая страница: {root}/query/Car.findAllPageable? offset=20 или {root]/query/Car.findAllPageable? limit=20&offset=20 Третья страница размером 10 записей: {root}/query/Car.findAllPageable? limit=10&offset=20 7 записей начиная с третей: {root}/query/Car.findAllPageable? limit=7&offset=3 Сервер всегда использует минимальный limit из укзанного в запросе и используемного в аннотиции. То есть

{root}/query/Car.findAllPageable? limit=100 вернет только 20 записей. При этом значение limit в ответе сервера будет 20, как в примере выше.Фильтрация полей При запросе данных иногда бывает нужно вернуть не всю запись, а только некоторые поля. К примеру, поле longDescr класса Car содержит текст внушительного размера, который мы не хотим передавать по сети. Именно для этого служит фильтрация полей.Фильтрация конфигурируется двумя параметрами:

fields — список полей, возвращаемых сервером. Поля разделяются запятыми. excludeFields — список полей, которые не возвращаются сервером. К примеру: GET {root}/entity/Car/1? fields=id, name, shortDescr Вернет только поля ud, name и shortDescr класса Car: { «id»: 1, «name»: «Mazda MX-5», «shortDescr»: «двухместный родстер», … } Тоже самое вернет и следующий запрос: GET {root}/entity/Car/1? excludeFields=longDescr При попытке использовать оба параметра fields и excludeFields в одном запросе, сервер вернет ошибку.Метаданные Метаданные содержат дополнительную информацию о ресурсе. В нашем слусае это ссылка на JSON схему ресурса и базовый URL.К примеру, метаданные для нашего класса Car выглядят так:

{ «name»: «Car», «links»: [ { «rel»: «alternate», «href»:»/metadata-catalog/entity/Car», «mediaType»: «application/schema+json» }, { «rel»: «canonical», «href»:»/metadata-catalog/entity/Car», «mediaType»: «application/json» }, { «rel»: «describes», «href»:»{root}/entity/Car» } ] } Получить метаданные для класса Car можно вот так: {root}/metadata-catalog/entity/Car Для запроса Car.findAll так: {root}/metadata-catalog/query/Car.findAll Еще один способ получения метаданных — вызов OPTIONS метода на базовый URL ресурса. OPTIONS /entity/Basket Сервер вернет ссылку на метаданные в заголовке Link c rel=«describedby» Link: ; rel=«describedby» Каталог ресурсов Каталог ресурсов, как оглавление книги, содержит метаданные для всех доступтых ресурсов. Это правильное место начала работы с незнакомой службой. Здесь всегда можно посмотреть доступные объкты и запросы.Каталог ресурсов доступен по следующему адресу:

GET /metadata-catalog Ответ сервера: { «items»: [ { «name»: «Car», … }, { «name»: «Car.findAll», … }, { «name»: «Car.findAllPageable», … } ], «links»: [ { «rel»: «canonical», «href»:»/metadata-catalog» } ] } Я урезал ответ сервера исключительно для читабельности. Медаданные для всех ресурсов выглядят также как указано в начале главы.JSON-схема ресурсов Хотя JSON схема пока не является утвержденным стандартом и работы над спецификацией еще не закончены, JPS-RS уже частично поддерживает draft 4 спецификации. Это касается формата вывода объектов и списка объектов.URL метаданных ресурса можно использовать и для получения его (ресурса) JSON схемы. Для этого выполняем HTTP GET запрос используя тип медиа «application/schema+json». То есть установив в HTTP заголовке «accept» значение «application/schema+json».

Получение схемы для класса Car:

GET /metadata-catalog/entity/Car HTTP/1.1 Accept-Encoding: gzip, deflate accept: application/schema+json Host: Proxy-Connection: Keep-Alive User-Agent: Apache-HttpClient/4.1.1 (java 1.5) Ответ сервера: { »$schema»:»/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»:»/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» } ] }

На этом все. Надеюсь, вам понравился обзор. Nightly builds EclipseLink можно скачать здесь: http://www.eclipse.org/eclipselink/downloads/nightly.php

© Habrahabr.ru