Весенний ХАТЕОАС. Встроенный ресурс + возможность его CRUD?

В типичной ситуации с встроенными ресурсами:

@Entity @Data
class Item {
    id, name
    ...
    @ManyToOne
    @JoinColumn(name="status", referencedColumnName="ID")
    private Status status;
}

@Entity @Data
class Status {
    id, name
    ...
    @JsonIgnore //break infinite reference loop during serialization
    @OneToMany(mappedBy="status")
    private List<Item> items;
}

Вместо ссылок на идентификаторы состояния в элементе JSON я хочу ВКЛЮЧИТЬ объект состояния в элемент JSON.

        {
            "itemName": "abc",
              ... ,
            "status": {
                "statusName":"ACTIVE",
                  ...
            }
            "_links": {
              ...
            }
        }

Мне удалось внедрить любое из следующего:

  • Пометка свойства status класса Item как @RestResource(exported=false)
    @Entity @Data
    class Item {
        ...
        @RestResource(exported=false) // <-- HERE
        @ManyToOne
        @JoinColumn(name="status", referencedColumnName="ID")
        private Status status;
  • Пометка интерфейса репозитория Статус @RepositoryRestResource(..., exported=false)
    @RepositoryRestResource(collectionResourceRel="statuses", path="status", exported=false)
    public interface StatusRepository extends JpaRepository<Status, String>
  • Удаление репозитория для объекта статуса
    // DELETED
    @RepositoryRestResource
    public interface StatusRepository extends JpaRepository<Status, String>{}

ВОПРОС:

Любой из них встраивает статус в элемент JSON, как я хочу, но у меня больше нет доступа к репозиторию статусов, чтобы получить объект статуса по его идентификатору или выполнить с ним какие-либо CRUD.

Как внедрить статус в родительский элемент JSON и сохранить статус CRUD через URL-адрес?


person Dmitry    schedule 23.06.2015    source источник


Ответы (1)


Я реализовал это следующим образом:

@Entity @Data
class Item {
    @Id
    @GeneratedValue(generator = "uuid2")
    @GenericGenerator(name = "uuid2", strategy = "uuid2")
    String id;
    String name

    @RestResource(exported = false) // <---- ADDED
    @ManyToOne
    @JoinColumn(name="status", referencedColumnName="ID")
    private Status status;
}

@Entity @Data
class Status {
    @Id
    @GeneratedValue(generator = "uuid2")
    @GenericGenerator(name = "uuid2", strategy = "uuid2")
    String id
    String name

    // <-------- DELETED REFERENCE TO PARENT OBJECT
    //@OneToMany(mappedBy="status")
    //private List<Item> items;
}

Существуют репозитории для обеих сущностей, поэтому можно выполнить CRUD и для сущности состояния.

@RepositoryRestResource(collectionResourceRel="items", path="items")
public interface StatusRepository extends JpaRepository<Item, String>
{}

@RepositoryRestResource(collectionResourceRel="statuses", path="statuses")
public interface StatusRepository extends JpaRepository<Status, String>
{}

Для будущих поколений я оставлю это здесь.

Для удобства:

1) Открытые идентификаторы для сущностей в JSON

/**
 * Exposing Ids as properties for entities specified
 */
@Configuration
public class ExposeIdConfig extends RepositoryRestMvcConfiguration {
  @Override
  protected void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
    config.exposeIdsFor(Item.class, Status.class);
  }
}

Таким образом, получение списка элементов выглядит так:

{
  "_links": {
    "self": {
      "href": "http://localhost:8080/app/items{?page,size,sort}",
      "templated": true
  }
},
"_embedded": {
  "as": [
    {
      "id": "29117425-f011-4ff9-8952-38b05d3df7f0",
      "name": "item 1",
      "status": {
        "id": "e9192ae7-29f8-4d5e-ad62-cad8d87de9e2",
        "name": "ACTIVE"
      },
      "_links": {
        "self": {
          "href": "http://localhost:8080/app/items/29117425-f011-4ff9-8952-38b05d3df7f0"
        }
  },
  ...
}
person Dmitry    schedule 25.06.2015