Статьи

Декларативные ссылки в Джерси 2.9 и выше

Пару месяцев назад я смотрел, как собираюсь разрабатывать новый REST API для проекта Oracle Cloud. Однажды я планировал использовать декларативную инъекцию ссылок, созданную в Jersey 1.x Марком Хэдли. К сожалению, это еще не было переадресовано, поэтому я побеседовал с руководителем проекта, и я взялся за

небольшую
 работу среднего размера по обновлению кода.

Одна из вещей, которая изменилась в новой версии, заключается в том, что в JAX-RS 2.0 есть  Link объект, поэтому вместо возможности вставлять только String и URI вы также можете вводить правильные атрибуты rel. Это означает, что существующие аннотации, закодированные Marc, были объединены в простой набор аннотаций как для заголовков Link, так и для внедренных свойств.

Эта функциональность доступно сейчас вместе с  простым примером. Оригинальная версия функции ,  что я совершил имеют некоторые серьезные ограничения, которые описаны ниже, вам потребуется версия Джерси поста 2.8 или вы можете построить 2,9-SNAPSHOT изображение , которое  содержит мои изменения в  настоящее время для реализации примера в этом блоге.

В этом блоге рассматривается использование этого нового API, чтобы обеспечить простое внедрение для API коллекций. Одним из распространенных шаблонов в сервисах RESTful, в частности, основанных на JSON, является наличие массива структурных связей на верхнем уровне структуры. Для целей этого блога я собираюсь следовать форме   гипермедиа типа Collection + JSON .

{ "collection" :
  {
    "version" : "1.0",
    "href" : "http://example.org/friends/?offset=10&limit=10",
    
    "links" : [
      {"rel" : "create", "href" : "http://example.org/friends/"}
      {"rel" : "next", "href" : "http://example.org/friends/?offset=20&limit=10"}
      {"rel" : "previous", "href" : "http://example.org/friends/?offset=0&limit=10"}
    ],
   
    "items" : [
       ...
    ]
  }
}

Так что я могу вставить ссылки в следующем виде, но для ясности здесь не хватает пучка котлов. Это не самый аккуратный код; но в более позднем цикле должно быть возможно просто несколько их Проект в настоящее время использует EL для доступа к свойствам — это дает преимущество, позволяющее записывать значения, поскольку вы можете представлять свойства. Я могу понять, что это не нравится некоторым; но я не уверен, вижу ли я какой-либо смысл в переходе на JavaScript в данный момент. Также не стоит удивляться аннотациям @Xml, я использую MOXy для генерации JSON — это не только XML.

{


  @XmlTransient
  private int limit, offset; // Getters for these

  @XmlTransient
  private int modelLimit; // Getters for these


  @InjectLink(
            resource = ItemsResource.class,
            method = "query",
            style = Style.ABSOLUTE,
            bindings = {@Binding(name = "offset", value="${instance.offset}"),
                @Binding(name = "limit", value="${instance.limit}")
            },
            rel = "self"
  )
  @XmlElement(name="link")
  private String href;

  @InjectLinks({
    @InjectLink(
          resource = ItemsResource.class,
          style = Style.ABSOLUTE,
          method = "query",
          condition = "${instance.offset + instance.limit < instance.modelLimit}",
          bindings = {
            @Binding(name = "offset", value = "${instance.offset + instance.limit}"),
            @Binding(name = "limit", value = "${instance.limit}")
          },
          rel = "next"
    ),
    @InjectLink(
          resource = ItemsResource.class,
          style = Style.ABSOLUTE,
          method = "query",
          condition = "${instance.offset - instance.limit >= 0}",
          bindings = {
            @Binding(name = "offset", value = "${instance.offset - instance.limit}"),
            @Binding(name = "limit", value = "${instance.limit}")
          },
          rel = "prev"
  )})
  @XmlElement(name="link")
  @XmlElementWrapper(name = "links")
  @XmlJavaTypeAdapter(Link.JaxbAdapter.class)
  List<Link> links;

  ....
}

Исходное портирование декларативного кода связывания, существующее в версии Jersey до 2.8, имело очень наивный код в отношении определения того, каким должен быть URI для конкретного ресурса, оно не могло работать с любыми ресурсами, которые не были в корне приложения. и не справится с параметрами запроса, которые так важны при работе с коллекциями.

Теоретически может быть несколько URI для определенного класса ресурсов; но этот код должен предполагать отображение 1: 1, текущая реализация содержит простой алгоритм, который использует метамодель Джерси, чтобы попытаться разработать структуру, если это не сработает, вы можете просто предоставить другую реализацию из ResourceMappingContext .

Некоторые могут спросить, почему я должен использовать эти уродливые аннотации, когда может быть проще просто ввести сам URI? Ну, причина в том, чтобы предоставить метаданные, которые могут использовать другие инструменты. Одна из моих следующих работ — расширить  эту работу  для создания расширений гипермедиа, и для этого мне нужны вышеуказанные метаданные. (Ожидание  одобрения запроса на  извлечение , прежде чем я действительно смогу в него попасть).

Наконец, стоит отметить, что у модели подкачки есть свои проблемы, которые становятся очевидными, если вы рассматриваете коллекцию REST как некий массив, который можно безопасно перелистывать. Одновременные обновления вместе с отсутствием состояния означают, что клиент никогда не может быть уверен, что у него есть полная модель, и он должен ожидать, что некоторые элементы будут видны несколько раз при обновлении модели. Вместо этого следует рассмотреть схемы на основе курсора или связывания, что является еще одним хорошим напоминанием о том, почему вы всегда должны рассматривать URI как непрозрачный — серверу может понадобиться изменить его структуру в будущем. Но это совсем другой блог для другого дня …..