Не могу опубликовать коллекцию

У меня есть простая сущность с сопоставленной одной коллекцией.

@Entity
public class Appointment Identifiable<Integer>   {  

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @JsonIgnore
    private Integer id;

    @Column(name="TRAK_NBR")
    private String trackNumber;

    @OneToMany(fetch =FetchType.EAGER, cascade= CascadeType.ALL)
    @JoinColumn(name="CNSM_APT_VER_WRK_I", nullable = false)
    private Set<Product> products = new HashSet<Product>();
}

@Entity
public class Product implements Identifiable<Integer> {

    @Id
    @Column(name = "CNSM_PRD_VER_WRK_I")
    @GeneratedValue(strategy = GenerationType.AUTO)
    @JsonIgnore
    private Integer id;

    @Column(name = "PRD_MDL_NBR")
    private String model;

    @Column(name = "PRD_SPEC_DSC")
    private String description;
}

В моем приложении, когда я включаю только PagingAndSortingRepository для назначения. Я могу вызвать команду POST со следующей полезной нагрузкой.

{
  "trackNumber" : "XYZ123",
  "products": [
    {"model" : "MODEL",
     "description" : "NAME"
    }]
}

Когда я добавляю PagingAndSortingRepository для продукта и пробую тот же POST, я получаю следующее сообщение об ошибке.

{
  "cause" : {
    "cause" : {
      "cause" : null,
      "message" : null
    },
    "message" : "(was java.lang.NullPointerException) (through reference chain: com..model.Appointment[\"products\"])"
  },
  "message" : "Could not read JSON: (was java.lang.NullPointerException) (through reference chain: com.model.Appointment[\"products\"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: com.model.AppointmentVerification[\"products\"])"
}

My GET payload with both Repositories returns this.  This is my desired format.  The link to products should be included

{
  "trackNumber" : "XYZ123", 
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/consumerappointment/appointments/70"
    },
    "products" : {
      "href" : "http://localhost:8080/consumerappointment/appointments/70/products"
  }
}

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

{
  "trackNumber" : "XYZ123",
  "products" : [ {
    "model" : "MODEL",
    "description" : "NAME",
  } ],
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/consumerappointment/appointments/1"
    }
  }
}

person zachariahyoung    schedule 22.06.2014    source источник


Ответы (1)


Давайте сделаем шаг назад и убедитесь, что вы понимаете, что здесь происходит: если репозиторий обнаружен, Spring Data REST предоставляет выделенный набор ресурсов для управления агрегатами, обрабатываемыми репозиторием через HTTP. Таким образом, если у вас есть репозитории для нескольких сущностей, связанных друг с другом, связь представлена ​​в виде ссылки. Вот почему вы видите продукты, встроенные только с AppointmentRepository и ссылкой products после создания ProductRepository.

Если вы хотите предоставить оба репозитория в качестве ресурсов, вам нужно передать URI экземпляров Product в полезной нагрузке для POST, чтобы создать Appointment. Это означает, что вместо публикации этого:

{ "trackNumber" : "XYZ123",
  "products": [
    { "model" : "MODEL",
      "description" : "NAME"
    }
  ]
}

вы бы сначала создали Product:

POST /products
{ "model" : "MODEL",
  "description" : "NAME" }

201 Created
Location: …/products/4711

Затем передайте идентификатор продукта полезной нагрузке Appointment:

{ "trackNumber" : "XYZ123",
  "products": [ "…/products/4711" ]}

В случае, если вы не хотите ничего из этого (во-первых, никаких ресурсов, открытых для Product, используйте @RepositoryRestResource(exported = false) на PersonRepository. Это все равно оставит вас с экземпляром компонента, созданным для репо, но без экспорта ресурсов и ресурсов, предоставленных для Appointments вернуться к встраиванию связанных Products.

person Oliver Drotbohm    schedule 24.06.2014
comment
Я вижу, это не очевидно из кода там. Я, конечно, не вдаюсь в детали дизайна вашей базы данных, но внешний ключ не означает, что он должен быть установлен в первую очередь. Это может быть просто ссылка, которая связывает продукт с встречей позже (отсюда и ваш Set). Тем не менее, я попытался объяснить, почему это работает так, как работает. Вполне возможно, что модель не соответствует вашему варианту использования, но вам не нужно разделять сводные корни, которые по определению имеют двунаправленную связь друг с другом. - person Oliver Drotbohm; 27.06.2014
comment
Моя таблица продуктов имеет ограничение внешнего ключа обратно в таблицу назначений. Таким образом, создание продуктов сначала не работает. Могу ли я изменить поведение POST, когда у меня есть оба репозитория? Мне нужно иметь возможность создавать встречи и продукты в одной транзакции, но при этом иметь ссылку на продукты в GET. - person zachariahyoung; 27.06.2014
comment
Да, просто предоставление реализованного вручную контроллера для соответствующего пути и метода HTTP должно помочь. Тем не менее, я думаю, что это маскирует фундаментальную проблему дизайна. - person Oliver Drotbohm; 27.06.2014
comment
Я создал небольшое приложение с реализованным вручную контроллером, о котором мы говорили. Я все еще не могу опубликовать полную полезную нагрузку, как я думал, что смогу. Похоже, у меня та же проблема, что и у этого jira.spring.io/browse/DATAREST-377. . Мой пример кода можно найти по адресу github.com/zachariahyoung/posterror. - person zachariahyoung; 24.09.2014