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
を導入しました。
いつものように、このチュートリアルのソースコードを必ずチェックしてください。