Не удается получить абстрактную сущность MappedSuperClass для работы с Spring Boot и JPA - PullRequest
0 голосов
/ 13 мая 2018

Я провел некоторое исследование и прошел это руководство .

Вот моя структура сущностей:

@MappedSuperClass
public abstract class Item{
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @Column(nullable = false)
    private String name;

    @OneToMany(cascade = CascadeType.ALL)
    @JoinColumn(name = "item_id")
    private Set<Picture> pictures = new HashSet<>();

}

Пример элемента 1:

@Entity
public class Coke extends Item{

    @Column
    private String cokeProperty;

    @Column
    private String cokeProperty2;
}

Пример элемента 2:

@Entity
public class Sprite extends Item{

    @Column
    private String spriteProperty;

    @Column
    private String spriteProperty2;
}

Класс изображения, используемый абстрактным классом Item:

@Entity
public class Picture {

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

    private String name;
}

Все они имеют конструкторы, геттеры и сеттеры, иtoString переопределяет.Я делаю это потому, что мне нужна таблица для Items, а затем отдельные таблицы для Coke и Sprite, каждая из которых содержит внешний ключ id из Items_table.Кроме того, я предполагаю, что это также создаст таблицу для Pictures, которая также имеет внешний ключ от Items_table.Однако я не могу понять, как реализовать Spring Boot и JPA для этого.Я думал, что это будет так же просто, как этот

Мой репозиторий для элементов с настроенной базой данных h2 в application.properties

@Repository
public interface ItemRepository<Item, Long>{
}

Мой Сервис, который реализует интерфейс ItemService и принимаетItemRepository bean:

@Service
public class ItemServiceImpl implements ItemService{

private ItemRepository repository;

public ItemServiceImpl(ItemRepository repository) {
    this.repository = repository;
}

@Override
public ResponseEntity<List<Item>> getAll(){
    return new ResponseEntity<>(repository.findAll(), HttpStatus.OK);
}

@Override
public ResponseEntity<Item> getById(Long id){
    Optional<Item> item = repository.findById(id);
    return new ResponseEntity<>(item.orElse(null), HttpStatus.OK);
}

@Override
public ResponseEntity<Item> create(Item item){
    return new ResponseEntity<>(repository.save(item), HttpStatus.CREATED);
}    }

А потом мой контроллер, который принимает ItemService bean:

@RestController
@RequestMapping("/api/items")
public class ItemController{

    private ItemService service;

    public ItemController(ItemService service) {
        this.service = service;
    }

    @GetMapping("")
    public ResponseEntity<List<Item>> findAll(){
        return service.getAll();
    }

    @GetMapping("/{id}")
    public ResponseEntity<Item> findById(@PathVariable(name = "id") Long id){
        return service.getById(id);
    }

    @PostMapping("")
    public ResponseEntity<Item> save(@RequestBody Item item){
        return service.create(item);
    }
}

Но когда я POST с Json Data, как

{
    "name": "Toyota Civic 3 days sale!!",
    "pictures": [
      {
        "name": "picture 1"
      },
      {
        "name": "picture 2"
      }
    ],
    "cokeProperty": "sweet",
    "cokeProperty2": "not healthy"
}

Я получаю эту ошибку:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Невозможно создать экземпляр com.example.demo.entities.product.Item (никаких создателей, таких как конструкция по умолчанию, не существует): абстрактныйтипы либо должны быть сопоставлены с конкретными типами, иметь собственный десериализатор или содержать дополнительную информацию о типе в [Source: (PushbackInputStream);строка: 1, столбец: 1]

Я также попробовал другую стратегию для своего абстрактного класса:

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)

Все еще нет сигары.Та же ошибка.Может ли кто-нибудь объяснить мне, как правильно использовать Spring Boot и JPA для абстрактных сущностей, расширенных другими сущностями?

1 Ответ

0 голосов
/ 14 мая 2018

javax.persistence's @MappedSuperClass не имеет прямого отношения к этой проблеме.Как указывается в сообщении об ошибке, причина в jackson-databind.

Поскольку Item является абстрактным классом, Джексон не может определить, какой конкретный класс ему следует создать, чтобы десериализовать сущность из JSON.Вот почему Item необходимо аннотировать ссылками на реализации:

import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;

@JsonTypeInfo(
  use = JsonTypeInfo.Id.NAME,
  include = JsonTypeInfo.As.PROPERTY, property = "type"
)
@JsonSubTypes({
    @JsonSubTypes.Type(value = Coke.class, name = "coke"),
    @JsonSubTypes.Type(value = Sprite.class, name = "sprite")
})
public abstract class Item {

   // no changes

}

Небольшое изменение также будет необходимо в JSON, поскольку оно должно указывать на тип реализации:

{
  "name": /* no changes  */,
  "type": "coke", /* new property */
  "pictures": /* no changes  */
}

Обратите внимание, что @JsonTypeInfo предоставляет несколько вариантов связывания его с реализацией, а не обязательно с полем "type".Имеются различные примеры и документация об этом.

Короткий тест позволяет показать, что Item теперь правильно десериализован:

String json = "{\n" +
    "    \"name\": \"Toyota Civic 3 days sale!!\",\n" +
    "    \"type\": \"coke\"," +
    "    \"pictures\": [\n" +
    "      {\n" +
    "        \"name\": \"picture 1\"\n" +
    "      },\n" +
    "      {\n" +
    "        \"name\": \"picture 2\"\n" +
    "      }\n" +
    "    ],\n" +
    "    \"cokeProperty\": \"sweet\",\n" +
    "    \"cokeProperty2\": \"not healthy\"\n" +
    "}";

ObjectMapper mapper = new ObjectMapper();

Item item = mapper.readValue(json, Item.class);

System.out.println(item);

// outputs:
// Coke(super=Item(id=0, name=Toyota Civic 3 days sale!!, pictures=[Picture(id=0, name=picture 2), Picture(id=0, name=picture 1)]), cokeProperty=sweet, cokeProperty2=not healthy)

Но этого изменения будет недостаточно, чтобы все заработалок вашим услугам.Как @Rujal Shrestha уже упоминает в своем комментарии, есть также проблемы с определениями репозиториев и отсутствием автопроводки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...