Автор оригинала: 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 , несомненно, позволит вам достичь вашей цели.