Рубрики
Без рубрики

Сопоставление записей Java со столбцами JSON с помощью Hibernate

Узнайте, как сопоставлять записи Java со столбцами JSON с помощью Oracle, SQL Server, PostgreSQL, MySQL и проекта Hibernate Types.

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