事象
Kotlinのdata classで プロパティ名がis始まりだとThymleaf側でgetterがないと怒られる
data class TestForm(
var id: Int = 0,
var isPublished: Boolean = false // これに対してgetterがないよと言われる。
}
<div th:value="${testForm.isPublished}"></div>
Bean property 'isPublished' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
原因
is始まりの場合は、getter、setterの命名規則が違うから。
プロパティ名 | getter | setter |
---|---|---|
hoge | getHoge | setHoge |
isHoge | isHoge | setHoge |
どうしてこうなってるのか
- Java の Bean規約に従っているため
以下でダウンロードできる。
https://download.oracle.com/otndocs/jcp/7224-javabeans-1.01-fr-spec-oth-JSpec/
上記から抜粋したもの
8.3.2 Boolean properties
In addition, for boolean properties, we allow a getter method to match the pattern:
public boolean is<PropertyName>();
This “is<PropertyName>” method may be provided instead of a “get<PropertyName>” method, or it may be provided in addition to a “get<PropertyName>” method.
In either case, if the “is<PropertyName>” method is present for a boolean property then we will
use the “is<PropertyName>” method to read the property value.
An example boolean property might be:
public boolean isMarsupial();
public void setMarsupial(boolean m);
is
始まりと言ったらbooleanだよね。だったらbooleanのプロパティのgetterもis
始まりにするね。
的なことが書かれている。
という理解で大体OKだが、自分の中で少し気になったので書いておく↓
今回のケースをもう少し厳密にかくと、
Kotlinは実行するためにJavaコードに変換している。
そのときのルールというのも一応ある。基本的には、上記JavaBeansの規約とほぼ同等。
https://kotlinlang.org/docs/java-to-kotlin-interop.html#properties
ほぼと言っているのは、Javaではbooleanのgetterは全てis始まりにするというのが軸になっている(風に見受けられる)が、kotlinのData ClassからJavaに変換する際は、boolenaかどうかではなく、単純に名前がis
始まりかを見ているから。
実際にkotlinのdata classをjavaのコードに変換してみてみるとわかりやすいです。
https://qiita.com/ke__kyukyun1828/items/384972110df2152bf530
例えば、booleanのtestFlagというプロパティのgetterは、JavaBeansの思想だとisTestFlag
になりそうだが、kotlin to Javaにおいては getTestFlag
とシンプルにgetを接頭辞につけたものになる。
対策
- getterを自分で作る(getterが2つできるのは気持ち悪い&何か問題起きそう)
- 例えば、 isTestというプロパティについて、 getIsTestを作る。
- アノテーションで任意のgetter、setter名にする(これならまだアリなのかも)
- https://kotlinlang.org/docs/java-to-kotlin-interop.html#handling-signature-clashes-with-jvmname
- 例:
@get:JvmName("isPublished") @set:JvmName("setIsPublished") var published: Boolean = false,
- そもそもis始まりの名前を使わない。
- 予期しない動作は防げるかも。でもちゃんとコメントしておかないと後であれこれis始まりがよくない?ってなりそう
まとめ
is始まりのプロパティ名のgetter、setterは別ルールが適用されるよ。
基本的に問題起きないけど、ライブラリとか(今回はThymelaf)で、このルールに対応できていないものもあるのでそういうところは気を付ける。