KotlinとJPAとの連携
1前書き
Kotlinの特徴の1つはリンクです:/kotlin-java-interoperability[Javaとの相互運用性]ライブラリ、そしてJPAは確かにこれらのうちの1つです。
このチュートリアルでは、JPAエンティティとして
Kotlinデータクラス
の使い方を探ります。
2依存関係
簡単にするために、JPAの実装としてHibernateを使用します。 Mavenプロジェクトに次の依存関係を追加する必要があります。
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.15.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-testing</artifactId>
<version>5.2.15.Final</version>
<scope>test</scope>
</dependency>
テストを実行するためにH2埋め込みデータベースも使用します。
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.196</version>
<scope>test</scope>
</dependency>
Kotlinでは、以下を使用します。
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
<version>1.2.30</version>
</dependency>
もちろん、最新バージョンのhttps://search.maven.org/classic/#search%7C1%7Cg%3A%22org.hibernate%22%20AND%20a%3A%22hibernate-core%22[Hibernate]、https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22com.h2database%22%20AND%20a%3A%22h2%22[H2]、https://search .maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.jetbrains.kotlin%22%20AND 20a%3A%22kotlin-stdlib-jdk8%22[Kotlin]はMaven Centralにあります。
3コンパイラプラグイン(jpa-plugin)
JPAを使用するには、エンティティクラスにパラメータなしのコンストラクタが必要です。
デフォルトで、Kotlinデータクラスはそれを持っていません、そしてそれらを生成するために我々はhttps://kotlinlang.org/docs/reference/compiler-plugins.html#jpa-support[jpa-plugin]を使う必要があるでしょう:
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>1.2.30</version>
<configuration>
<compilerPlugins>
<plugin>jpa</plugin>
</compilerPlugins>
<jvmTarget>1.8</jvmTarget>
</configuration>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-noarg</artifactId>
<version>1.2.30</version>
</dependency>
</dependencies>
<!--...-->
</plugin>
4 Kotlinデータクラスを使ったJPA
前の設定が完了したら、JPAをデータクラスと共に使用する準備が整いました。
このように、
id
と
name
の2つの属性を持つ
Person
データクラスの作成を始めましょう。
@Entity
data class Person(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Int,
@Column(nullable = false)
val name: String
)
ご覧のとおり、
@ Entity、@Column
、
@ Id
など、JPAのアノテーションを自由に使用できます。
私たちの実体が動いているのを見るために、次のテストを作成します
@Test
fun givenPerson__whenSaved__thenFound() {
doInHibernate(({ this.sessionFactory() }), { session ->
val personToSave = Person(0, "John")
session.persist(personToSave)
val personFound = session.find(Person::class.java, personToSave.id)
session.refresh(personFound)
assertTrue(personToSave == personFound)
})
}
ロギングを有効にしてテストを実行すると、次のような結果が得られます。
Hibernate: insert into Person (id, name) values (null, ?)
Hibernate: select person0__.id as id1__0__0__, person0__.name as name2__0__0__ from Person person0__ where person0__.id=?
それはすべてが順調に進んでいることの指標です。 +実行時に
jpa-plugin
を使用しない場合、デフォルトのコンストラクタがないため、__InstantiationExceptionが発生します。
javax.persistence.PersistenceException: org.hibernate.InstantiationException: No default constructor for entity: : com.baeldung.entity.Person
それでは、もう一度
null
値でテストします。これを行うには、新しい属性
email
と
@ OneToMany
関係を使用して
Person
エンティティを拡張しましょう。
//...
@Column(nullable = true)
val email: String? = null,
@Column(nullable = true)
@OneToMany(cascade =[CascadeType.ALL])
val phoneNumbers: List<PhoneNumber>? = null
email
フィールドと
phoneNumbers
フィールドはNULL可能であるため、疑問符で宣言されていることもわかります。
PhoneNumber
エンティティには、
id
と
number
の2つの属性があります。
@Entity
data class PhoneNumber(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Int,
@Column(nullable = false)
val number: String
)
テストでこれを確認しましょう。
@Test
fun givenPersonWithNullFields__whenSaved__thenFound() {
doInHibernate(({ this.sessionFactory() }), { session ->
val personToSave = Person(0, "John", null, null)
session.persist(personToSave)
val personFound = session.find(Person::class.java, personToSave.id)
session.refresh(personFound)
assertTrue(personToSave == personFound)
})
}
今回は、1つのinsert文を受け取ります。
Hibernate: insert into Person (id, email, name) values (null, ?, ?)
Hibernate: select person0__.id as id1__0__1__, person0__.email as email2__0__1__, person0__.name as name3__0__1__, phonenumbe1__.Person__id as Person__i1__1__3__, phonenumbe2__.id as phoneNum2__1__3__, phonenumbe2__.id as id1__2__0__, phonenumbe2__.number as number2__2__0__ from Person person0__ left outer join Person__PhoneNumber phonenumbe1__ on person0__.id=phonenumbe1__.Person__id left outer join PhoneNumber phonenumbe2__ on phonenumbe1__.phoneNumbers__id=phonenumbe2__.id where person0__.id=?
出力を検証するために
null
データなしでもう一度テストしましょう。
@Test
fun givenPersonWithFullData__whenSaved__thenFound() {
doInHibernate(({ this.sessionFactory() }), { session ->
val personToSave = Person(
0,
"John",
"[email protected]",
Arrays.asList(PhoneNumber(0, "202-555-0171"), PhoneNumber(0, "202-555-0102")))
session.persist(personToSave)
val personFound = session.find(Person::class.java, personToSave.id)
session.refresh(personFound)
assertTrue(personToSave == personFound)
})
}
そして、ご覧のとおり、今度は3つのinsertステートメントが得られます。
Hibernate: insert into Person (id, email, name) values (null, ?, ?)
Hibernate: insert into PhoneNumber (id, number) values (null, ?)
Hibernate: insert into PhoneNumber (id, number) values (null, ?)
5結論
この簡単な記事では、jpa-pluginとHibernateを使ってKotlinデータクラスをJPAと統合する方法の例を見ました。
いつものように、ソースコードは利用可能です
https://github.com/eugenp/tutorials/tree/master/spring-mvc-kotlin
[over
GitHubで。