事象 : 画面からsubmit処理を実行したらBeanに値を設定できないと怒られた
- 環境
- Windows10 64bit バージョン1909
- openjdk 11 2018-09-25
- Eclipse IDE for Enterprise Java Developers Version: 2020-09 (4.17.0)
- JSF 2.3.9
- Payara Server 5.194
javax.el.PropertyNotWritableException: /admin/ponsuke/ponsuke.xhtml @52,92 value="#{item.mailAddress}": The class 'jp.co.my.app.Item' does not have a writable property 'mailAddress'.
at com.sun.faces.facelets.el.TagValueExpression.setValue(TagValueExpression.java:99)
at javax.faces.component.UIInput.updateModel(UIInput.java:859)
at javax.faces.component.UIInput.processUpdates(UIInput.java:773)
at com.sun.faces.facelets.component.UIRepeat.process(UIRepeat.java:571)
Beanに・・・・
<!-- 省略 -->
<ui:repeat var="category" varStatus="index" value="#{ponsukeController.categories}">
<ui:repeat var="item" varStatus="status" value="#{category.itemList}">
<td class="form-inline">
<h:inputText value="#{item.mailAddress}" />
<!-- 省略 -->
Setterがない?
// 省略
/** カテゴリ情報リスト. */
@Getter
@Setter
private List<Category> categories;
// 省略
原因 : 子クラスに@Setterがないから
あぁぁぁぁ、@Valueに@Setterは含まれていなかった・・・
In practice,
@Valueis shorthand for: final@ToString@EqualsAndHashCode@AllArgsConstructor@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)@Getter, except that explicitly including an implementation of any of the relevant methods simply means that part won't be generated and no warning will be emitted.
@Value - projectlombok.org
import lombok.Value;
@Value
public class Category {
List<Item> itemList;
}
import lombok.Value;
@Value
public class Item {
int itemId;
String mailAddress;
}
対応 : 設定するプロパティのあるクラスのアノテーションを変更する
今回は@Valueがくっついていて、他のところで@AllArgsConstructorの役割を使っているので、
[@Getter @AllArgsConstructor] + [@Setter] = [@Data @AllArgsConstructor]
へ変更することにした。
class CategoryはプロパティがListで中身しか変更しないのでアノテーションは変更しない。
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class Item {
// 省略
ちなみに
itemListとmailAddressプロパティ個別に@Setterをつけるとコンパイルエラーになる。
classに@Valueに加えて@SetterをつけてもPropertyNotWritableExceptionが発生した。
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)があるためであろうなぁ・・・と思う。
To add final to each (instance) field, use
@FieldDefaults(makeFinal=true). Any non-final field which must remain nonfinal can be annotated with@NonFinal(also in the lombok.experimental package).
@FieldDefaults - projectlombok.org