Hibernateを使ってJSONオブジェクトを永続化する

1概要

プロジェクトによっては、JSONオブジェクトをリレーショナルデータベースに保持する必要がある場合があります。

このチュートリアルでは、JSONオブジェクトを取得し、それをリレーショナルデータベースに保持する方法を説明します。

この機能を提供する利用可能なフレームワークがいくつかありますが、https://www.baeldung.com/hibernate-5-spring[Hibernate]およびhttps://www.baeldungのみを使用して、いくつかの単純で一般的なオプションを調べます。 com/jackson[ジャクソン]。

2依存関係

このチュートリアルではhttps://search.maven.org/search?q=g:org.hibernate%20AND%20a:hibernate-core[basic Hibernate Core依存関係]を使用します。

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>5.4.0.Final</version>
</dependency>

JSONライブラリとしてhttps://search.maven.org/search?q=g:com.fasterxml.jackson.core%20AND%20a:jackson-databind[Jackson]も使用します。

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.8</version>
</dependency>
  • これらの手法はこれら2つのライブラリに限定されないことに注意してください。

3メソッドのシリアライズとデシリアライズ

リレーショナルデータベースでJSONオブジェクトを永続化する最も基本的な方法は、永続化する前に オブジェクトを String に変換することです。それから、データベースからそれを取得するときに、それをオブジェクトに変換します。

いくつかの方法でこれを行うことができます。

私たちが最初に見るのは、** カスタムのシリアライズとデシリアライズのメソッドを使うことです。

まず、顧客の姓名、およびその顧客に関する属性を格納する単純な Customer エンティティから始めます。

標準のJSONオブジェクトはこれらの属性を HashMap として表します。そのため、ここではこれを使用します。

@Entity
@Table(name = "Customers")
public class Customer {

    @Id
    private int id;

    private String firstName;

    private String lastName;

    private String customerAttributeJSON;

    @Convert(converter = HashMapConverter.class)
    private Map<String, Object> customerAttributes;
}

属性を別のテーブルに保存するのではなく、 Customers テーブルの列に** JSONとして保存します。これにより、スキーマの複雑さを軽減し、クエリのパフォーマンスを向上させることができます。

まず、 customerAttributes を取得してJSON文字列に変換する直列化メソッドを作成します** 。

public void serializeCustomerAttributes() throws JsonProcessingException {
    this.customerAttributeJSON = objectMapper.writeValueAsString(customerAttributes);
}

永続化する前にこのメソッドを手動で呼び出すことも、 setCustomerAttributes メソッドから呼び出すことで属性が更新されるたびにJSON文字列も更新することができます。

次に、データベースから Customer を取得するときに** JSON文字列を HashMap オブジェクトに逆シリアル化するメソッドを作成します。

public void deserializeCustomerAttributes() throws IOException {
    this.customerAttributes = objectMapper.readValue(customerAttributeJSON, HashMap.class);
}

繰り返しますが、このメソッドを呼び出すことができる場所はいくつかありますが、この例では手動で呼び出します。

したがって、 Customer オブジェクトを永続化して取得すると、次のようになります。

@Test
public void whenStoringAJsonColumn__thenDeserializedVersionMatches() {
    Customer customer = new Customer();
    customer.setFirstName("first name");
    customer.setLastName("last name");

    Map<String, Object> attributes = new HashMap<>();
    attributes.put("address", "123 Main Street");
    attributes.put("zipcode", 12345);

    customer.setCustomerAttributes(attributes);
    customer.serializeCustomerAttributes();

    String serialized = customer.getCustomerAttributeJSON();

    customer.setCustomerAttributeJSON(serialized);
    customer.deserializeCustomerAttributes();

    assertEquals(attributes, customer.getCustomerAttributes());
}

4属性コンバーター

  • JPA 2.1以降を使用している場合は、 AttributeConverters を使用してこのプロセスを効率化できます。

まず、 AttributeConverter の実装を作成します。以前のコードを再利用します。

public class HashMapConverter implements AttributeConverter<Map<String, Object>, String> {

    @Override
    public String convertToDatabaseColumn(Map<String, Object> customerInfo) {

        String customerInfoJson = null;
        try {
            customerInfoJson = objectMapper.writeValueAsString(customerInfo);
        } catch (final JsonProcessingException e) {
            logger.error("JSON writing error", e);
        }

        return customerInfoJson;
    }

    @Override
    public Map<String, Object> convertToEntityAttribute(String customerInfoJSON) {

        Map<String, Object> customerInfo = null;
        try {
            customerInfo = objectMapper.readValue(customerInfoJSON, Map.class);
        } catch (final IOException e) {
            logger.error("JSON reading error", e);
        }

        return customerInfo;
    }

}

次に、Hibernateに customerAttributes フィールドに新しい AttributeConverter を使用するように指示して、完了です。

@Convert(converter = HashMapConverter.class)
private Map<String, Object> customerAttributes;
  • このアプローチでは、Hibernateが私たちのためにそれを引き受けるので ** 手動でシリアライズとデシリアライズのメソッドを呼び出す必要はもうありません。

通常は Customer オブジェクトを単純に保存および取得できます。

5結論

この記事では、HibernateとJacksonを使ってJSONオブジェクトを永続化する方法のいくつかの例を見ました。

最初の例では、カスタムのシリアライズメソッドとデシリアライズメソッドを使用した単純で互換性のあるメソッドを見ました。次に、コードを単純化するための強力な方法として AttributeConverters を導入しました。

いつものように、このチュートリアルのソースコードを必ずチェックしてください。