3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Java/Kotlin/JPA】entityをnullセーフにしたい

Posted at

こんにちは。こまつです。

概要

Java8からJavaにもnullセーフが入りました。optionalを使えばヌルポがなくなります。
とか言いながら、Java+SpringDataJPAではoptionalをマッピングできません。カスですね。
Kotlinならどうなるんでしょうか。

前提

nullセーフとはヌルポになりうるコードをコンパイルエラーにしてくれるやつです。
Entityは特にnullセーフにする重要度が高いです。

nulセーフサンプル.java
String randomStr = new Random().nextBoolean() ? "わーい" : null; // nullかも知れない文字列
Integer length1 = randomStr.length(); // 1/2でヌルポ
Optional<String> str = Optional.ofNullable(randomStr); // null知 文字列型定義
Integer length2 = str.length(); // コンパイルエラー
Integer length3 = str.map(s -> s.length()).orElseGet(() -> 0); // コンパイルOK(nullであればlength=0)

Java+JPAのOptionalはこうしたい。けどできない

肝心のOptional部分でJPAのエラーとなります。

javaでjpa.java
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
public class Post {
  @Id
  private Long id;
  @Column(length = 100, nullable = false)
  private String title;
  @Column(length = 1000, nullable = true) // nullを許容
  private Optional<String> body; <----こうしたいがエラーになる
}

のでJava+JPAではこうするしかない(たぶん)

AllArgsConstructorを諦めてコンストラクタ、アクセサを自前で実装しています。

sono1.java
@Entity
@NoArgsConstructor
@Setter
public class Post {
  @Id
  private Long id;
  @Column(length = 100, nullable = false)
  private String title;
  @Column(length = 1000, nullable = true) // nullを許容 
  private String body;

  public Post(Optional<Long> id, String title, Optional<String> body) {
    this.id = id.orElseGet(() -> null);
    this.title = title;
    this.body = body.orElseGet(() -> null);
  }

  public Long getId() {
    return id;
  }

  public String getTitle() {
    return title;
  }

  public Optional<String> getBody() {
    return Optional.ofNullable(body);
  }
}

Kotlin+JPAなら

普通に実装すればnullセーフのプロパティを持てます。

Entity.kt
@Entity
data class Post(
  @Id
  val id: Long,
  @Column(length = 100, nullable = false)
  val title: String,
  @Column(length = 1000, nullable = true) // nullを許容
  val body: String?, <---- JavaOptional<String>と等価
): Serializable

実際に動くか登録してみます。

実際に登録してみる.kt
val post = Post(1, "nullじゃない", "内容!")
postRepository.save(post)
val post2 = Post(2, "nullなんです", null)
postRepository.save(post2)

想定通りに登録されているようです。取得も問題ありませんでした。
スクリーンショット 2022-09-13 12.15.15.png

まとめ

この問題はJavaに対する大きな不満点でしたが、Kotlinでは解消されているようです。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?