Я всегда избегал отношений @xToX в своих API, но, наконец, хотел попробовать, и я борюсь с этим.Мне удалось заставить методы get возвращать мне правильную информацию с любой рекурсивностью (по крайней мере, я сделал часть), и теперь я хочу опубликовать данные в моем API с этими взаимосвязями (и, кажется, работает до сих пор).
Итак, у меня есть несколько объектов: книга, стиль книги, категория книг и автор.У книги есть только один автор (даже если она иногда ложная, но, поскольку я читаю только Sci-Fi, она сделает свое дело), и у автора есть много книг (то же самое для категории).И у стиля может быть много книг, также у книг может быть много стилей.
Итак, я выбрал @ManyToOne
для свойства автора книги и @OneToMany
для свойства книги автора (то же самое для категории).И между стилем и буквой @ManyToMany
Я хочу иметь возможность опубликовать книгу в своем API следующим образом, используя идентификаторы автора и стиля:
{
"isbn": "15867jhg8",
"title": "Le portrait de Dorian Gray",
"author": 1,
"category":1,
"style": [1,2,3]
}
У меня естьмои свойства помечены @JsonBackReference
, @JsonManagedReference
, @JsonSerialize
, @JsonIdentityInfo
, но я действительно думаю, что мог бы сделать это слишком много ...
Я не уверен в том, как я использовал@JsonSerialize, ни @JsonIdentityInfo.Я опустил бесполезные свойства, чтобы сделать пример «простым».
Итак, давайте углубимся.
Сначала класс Book:
@Entity
@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id"
)
public class Book implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(updatable = false, nullable = false)
private Integer id;
private String isbn;
private String title;
@ManyToOne
@JoinColumn(name="category_id", nullable = false)
@JsonBackReference(value = "category")
private BookCategory category;
@ManyToOne
@JoinColumn(name="author_id", nullable = false)
@JsonBackReference(value = "author")
private Author author;
@ManyToMany
@JsonManagedReference(value = "styles")
@JsonSerialize(using = BookStyleListSerializer.class)
private List <BookStyle> styles;
}
Затем класс автора:
@Entity
@JsonIdentityInfo (
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id"
)
public class Author implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(updatable = false, nullable = false)
private Integer id;
@OneToMany(mappedBy = "author")
@JsonManagedReference(value = "authorBooks")
@JsonSerialize(using = BookListSerializer.class)
private List <Book> books;
}
Поскольку категория совершенно одинакова, я только вставляю свойство books:
@OneToMany(mappedBy = "category")
@JsonManagedReference(value = "categoryBooks")
@JsonSerialize(using = BookListSerializer.class)
private List <Book> books;
И, наконец, мой класс bookStyle:
@Entity
@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id"
)
public class BookStyle implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(updatable = false, nullable = false)
private Integer id;
@ManyToMany
@JsonManagedReference(value = "styleBooks")
@JsonSerialize(using = BookListSerializer.class)
private List <Book> books;
}
Сериализатор один и тот же, меняется только тип:
public class BookStyleListSerializer extends StdSerializer <List <BookStyle>> {
public BookStyleListSerializer() {
this(null);
}
public BookStyleListSerializer(Class<List<BookStyle>> t) {
super(t);
}
@Override
public void serialize(List <BookStyle> bookStyles, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
List<Integer> ids = new ArrayList <> ( );
for (BookStyle style: bookStyles){
ids.add(style.getId ());
}
jsonGenerator.writeObject ( ids );
}
}
Из того, что я понял (и, поскольку английский не является моим родным языком, я мог бы неправильно понять кое-что здесь и там во время кодирования):
@JsonBackReference
должен использоваться для свойства, которое мы не хотим сериализовать, в отличие от @JsonManagedReference
@JsonSerialize
- это пользовательский сериализатор, так чтоэлементы будут сериализованы так, как мы хотим (в данном случае, только с использованием идентификаторов)
И, как это может быть очевидно для некоторых из вас: ничего из того, что я кодировал, не работает для публикации данных,вот исключение, как я получил, когда я публикую что-то через API (и это в два раза, неошибка вставки копии):
.c.j.MappingJackson2HttpMessageConverter : Failed to evaluate Jackson deserialization for type [[simple type, class com.rz.librarian.domain.entity.Author]]: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot handle managed/back reference 'categoryBooks': no back reference property found from type [collection type; class java.util.List, contains [simple type, class com.rz.librarian.domain.entity.Book]]
.c.j.MappingJackson2HttpMessageConverter : Failed to evaluate Jackson deserialization for type [[simple type, class com.rz.librarian.domain.entity.Author]]: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot handle managed/back reference 'categoryBooks': no back reference property found from type [collection type; class java.util.List, contains [simple type, class com.rz.librarian.domain.entity.Book]]
Я много чего перепробовал, но после трех дней по этому вопросу я хотел попросить (плакать?) помощи.
Спасибо, ребята, и извините за длинный пост!