Автор оригинала: Vlad Mihalcea.
Вступление
В этой статье я собираюсь объяснить, как мы можем сопоставлять записи Java со столбцами JSON при использовании Hibernate.
Поскольку Hibernate ORM не предлагает встроенной поддержки JSON, мы собираемся использовать библиотеку Hiberate Types , которая позволяет сопоставлять атрибуты сущностей с типами столбцов JSON, независимо от того, используете ли вы Oracle, SQL Server, PostgreSQL или MySQL.
Записи Java
Как я объяснил в этой статье , записи Java-отличный способ создания структурированных типов данных.
В нашем случае мы хотим инкапсулировать информацию о книге в следующую структуру данных Книга :
Чтобы создать приведенную выше структуру Книга , мы можем использовать следующее определение записи Java:
public record BookRecord (
String title,
String author,
String publisher,
Long priceInCents,
URL url
) {}
Как сериализовать записи Java в JSON с помощью Jackson
Как я объяснил в этой статье , записи Java нельзя использовать в качестве сущностей JPA или Hibernate, но вы можете использовать их в качестве основных атрибутов:
Поскольку Hibernate ORM не имеет встроенной поддержки записей Java, нам необходимо предоставить пользовательский тип Hibernate для сопоставления записей Java с соответствующим типом столбца базы данных, и одним из вариантов является сохранение записи Java в столбце JSON.
Чтобы убедиться, что записи Java правильно маршалированы в объект JSON и не заштрихованы обратно в запись Java , нам нужно изменить BookRecord , как это:
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
public record BookRecord (
String title,
String author,
String publisher,
Long priceInCents,
URL url
) implements Serializable {
@JsonCreator
public BookRecord(
@JsonProperty("title") String title,
@JsonProperty("author") String author,
@JsonProperty("publisher") String publisher,
@JsonProperty("priceInCents") String priceInCents,
@JsonProperty("url") String url) {
this(
title,
author,
publisher,
longValue(priceInCents),
urlValue(url)
);
}
}
Для правильного преобразования записи Java в объект JSON с помощью Jackson необходимы следующие изменения:
- аннотация
@JsonAutoDetectпозволяет Джексону получать доступ к закрытым полям записи Java при сериализации или десериализации ее из строкового представления, отправленного в базу данных - интерфейс
Сериализуемыйнеобходим, поскольку, согласно спецификации JPA, каждый атрибут сущности должен быть сериализуемым с использованием механизма сериализации Java. - аннотация
@JsonCreatorбыла добавлена, чтобы отметить, что Джексон может вызвать дополнительный конструктор для передачи атрибута JSON на основе Strong для инициализации полей записей Java.
Как сопоставить записи Java со столбцами JSON с помощью Hibernate
Платформа Hibernate Types поддерживает Oracle, SQL Server, PostgreSQL и MySQL, поэтому в зависимости от компонента database engine и соответствующего типа столбца JSON вы можете использовать один из следующих вариантов.
Для Oracle, SQL Server, MySQL, PostgreSQL и H2 вы можете использовать тип Json из проекта Типы гибернации для сопоставления записей Java со столбцами JSON.
В случае, если вы используете MySQL, вы можете использовать выделенный JSON тип столбца для хранения свойств атрибутов, в то время как для PostgreSQL вам необходимо использовать jsonb тип столбца.
Таким образом, объект Книга будет отображен следующим образом:
@Entity(name = "Book")
@Table(name = "book")
@TypeDef(
typeClass = JsonType.class,
defaultForType = BookRecord.class
)
public class Book {
@Id
@GeneratedValue
private Long id;
@NaturalId
private String isbn;
@Column(columnDefinition = "JSON")
private BookRecord properties;
//Getters and setters omitted for brevity
}
Сохранение записей Java в столбцах JSON с использованием режима гибернации
При сохранении следующей Книги сущности:
entityManager.persist(
new Book()
.setIsbn("978-9730228236")
.setProperties(
new BookRecord(
"High-Performance Java Persistence",
"Vlad Mihalcea",
"Amazon",
4499L,
null
)
)
);
Hibernate создает следующую инструкцию INSERT:
INSERT INTO book (
isbn,
properties,
id
)
VALUES (
'978-9730228236',
{
"title":"High-Performance Java Persistence",
"author":"Vlad Mihalcea",
"publisher":"Amazon",
"priceInCents":4499,
"url":null
},
1
)
Извлечение записей Java в столбцы JSON с помощью режима гибернации
При извлечении сущности Книга мы видим, что получаем ожидаемую запись Книга :
Book book = entityManager
.unwrap(Session.class)
.bySimpleNaturalId(Book.class)
.load("978-9730228236");
BookRecord bookRecord = book.getProperties();
assertEquals(
"High-Performance Java Persistence",
bookRecord.title()
);
assertEquals(
"Vlad Mihalcea",
bookRecord.author()
);
Обновление Записей Java
Записи Java неизменяемы, поэтому, когда мы хотим изменить атрибут properties , мы должны создать новый экземпляр записи книги , например:
book.setProperties(
new BookRecord(
bookRecord.title(),
bookRecord.author(),
bookRecord.publisher(),
bookRecord.priceInCents(),
urlValue("https://www.amazon.com/dp/973022823X/")
)
);
Когда контекст сохранения сброшен, Hibernate создает следующую инструкцию ОБНОВЛЕНИЯ:
UPDATE
book
SET
properties = {
"title":"High-Performance Java Persistence",
"author":"Vlad Mihalcea",
"publisher":"Amazon",
"priceInCents":4499,
"url":"https://www.amazon.com/dp/973022823X/"
}
WHERE
id = 1
Круто, правда?
Вывод
Как вы можете видеть, записи Java очень удобны в использовании, когда вы хотите структурировать свои данные с помощью неизменяемых объектов, компактных для записи и гибких для настройки. Добавив аннотации Джексона и дополнительный конструктор, мы смогли сериализовать запись Java в объект JSON при сохранении сущности Book в базе данных и десериализовать тип столбца JSON обратно в его представление записи Java.
Если вы хотите отобразить атрибут сущности в виде записи Java и сохранить его в столбце JSON, то проект Hibernate Types , несомненно, позволит вам достичь вашей цели.