Spring Data REST Вступил в наследование

У меня есть Spring Data Repository над одним объектом JPA. Этот объект подклассифицирован через объединенное наследование.

Spring У данных REST есть проблема, интерпретирующая эту структуру, по крайней мере автоматически. Или, может быть, я не понимаю использование Inheritance.JOINED

Любой запрос для любого объекта с Event возвращает следующее:

{
    cause: null,
    message: "Cannot create self link for class com.foo.event.SubEvent! No persistent entity found!"
}

Возможно, я слишком много прошу, чтобы этот проект знал, как с этим справиться, но есть ли способ обхода, который бы сгруппировал все мои Events под тем же /events? Может быть, даже разрешить мне фильтровать по типу?

Я оставил основы структуры приложения ниже.

Event.java

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@JsonTypeInfo(use = Id.NAME, include = As.PROPERTY, property = "type")
@JsonSubTypes({
  @Type(value = SubEvent.class), 
  ...
})
...
public class Event {
    @Id
    private long id;
    ...
}

SubEvent.java

@Entity
public class SubEvent extends Event {
    private String code;
    ...
}

EventRepository.java

@RepositoryRestResource(path = "events")
public interface EventRepository extends PagingAndSortingRepository<Event, Long> {
    ...    
}

Ответ 1

Я думаю, что вам не хватает Discriminator, чтобы JPA понял, какой подкласс использовать для данного объекта (как он знает иначе?).

Я склонен использовать абстрактные классы для наемных работников на основе подкласса, поэтому здесь приведен пример, подходящий для вас:

Event.java

@Entity
@DiscriminatorColumn(name = "type")
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Event {
    @Id
    @GeneratedValue
    public Long id;

    public String type;
}

SubEvent.java

@Entity
@DiscriminatorValue("subevent")
@PrimaryKeyJoinColumn(name = "event_id")
public class PeeringService extends Service {
    private String code;
}

С приведенным выше кодом вы заметите что-то нечетное - при создании пути ресурса для одного из этих объектов предполагается, что у вас есть Repository для каждого подкласса и генерирует что-то вроде этого:

{
  "type" : "subevent",
  "code" : "bacon",
  "_links" : {
    "self" : {
      "href" : "http://localhost:8081/subEvents/1"
    },
    "peeringService" : {
      "href" : "http://localhost:8081/subEvents/1"
    }
  }
}

Это довольно легко исправить, но вам просто нужно добавить следующую аннотацию в базовый класс:

@RestResource(path = "events")

И он будет генерировать пути ресурсов, которые вы ожидаете!

Надеюсь, что это поможет:)

Ответ 2

Я попробовал вас в классе в простом проекте загрузки spring, и они не дали мне никаких проблем, и я не мог воспроизвести проблему, с которой вы сталкиваетесь. Однако поиск в приведенном вами сообщении об ошибке дает пару сообщений, которые предполагают, что вам нужно создать репозиторий SubEvent, даже если вы его не используете, и что проблема возникает в более сложных проектах, например, с использованием REST.

Ссылка: Невозможно создать самостоятельную ссылку для класса X. Не найден постоянный объект.

Как выбрать MappingContext в spring -data-jpa (2x) + spring -rest-webmvc?

Итак, попробуйте добавить репозиторий SubEvent:

interface SubEventRepository extends CrudRepository<SubEvent, Long> {
}

Ответ 3

Я думаю, что проблема не имеет ничего общего с JPA, но это скорее круговая проблема сериализации. Поскольку вы не показали свою сущность, я могу только предположить, что сущность Subevent имеет отношение к другому (Sub) событию и что один Subevent ссылается на себя, что приводит к этой проблеме. Конечно, также возможно, что отношения не являются прямыми, а скорее некоторыми другими классами сущностей, такими как SubEvent → EntityG → Event.

Чтобы решить эту проблему, просто используйте DTO, в котором отображаются только все поля SubEvent, кроме тех, которые производят циклическую зависимость.

Ответ 4

Я опробовал немало вариантов, и никто не работал, как ожидалось, и всегда имел проблемы в одной точке (создание ссылок, сопоставление репозитория, сопоставление URL-адресов и т.д.).

Даже для разделенных репозиториев (по одному для каждого подтипа) я не имел успеха. Мое "грязное, а не рабочее" решение заключалось в том, чтобы постинвестировать ссылки для всех подтипов, используя реализацию ResourceProcessor. Эта реализация в основном заменила имя подтипа именем типа на каждой ссылке, присутствующей на ресурсе.

Кроме того, был введен RelProvider для обработки имен свойств разных типов.