List[T]をエンコードしたかったのですが、公式サンプルに載ってなかったのでメモ。

環境


  • Scala 2.12.7
  • circe 0.10

やりたいこと


こんな感じのcase classがあったとして、これの配列List[User]をcirceを使ってエンコードしたい。

1
2
3
4
case class User(
id: Int,
name: String,
)

基本的なエンコード


これは公式ドキュメントにも書いてあって、下記のように書くことができる。

1
2
3
4
5
6
import io.circe._
import io.circe.generic.semiauto._

implicit val encodeUser: Encoder[User] = deriveEncoder[User]

User(1, "YoshinoriN").asJson

implicit valの部分はシンプルに下記のように書くこともできる。

1
implicit val encodeUser: Encoder[User] = deriveEncoder[User]

配列のエンコード


では、上記のようにList[User]もエンコードできるのでは?と思って下記のように書くとコンパイル時に例外が発生する。ちなみにIntelliJ上ではエラー表示されない。

1
2
3
implicit val encodeUsers: Encoder[List[User]] = deriveEncoder[List[User]]

List(User(1,"YoshinoriN"),User(2,"Hoge")).asJson

例外が出る。

1
could not find Lazy implicit value of type io.circe.generic.encoding.DerivedObjectEncoder[List[User]]

じゃあ、結局のところ配列をエンコードするにはどうすればいいのかというとEncoder.encodeListというメソッドが存在するので、それを使えばいいです。

1
2
3
4
implicit val encodeUser: Encoder[User] = deriveEncoder[User]
implicit val encodeUsers: Encoder[List[User]] = Encoder.encodeList[User]

List(User(1,"YoshinoriN"),User(2,"Hoge")).asJson

Encoder.encodeList[User]は暗黙のパラメータでEncoder[User]を要求するのでUserのエンコードも書く必要があります。上記でいう一行目です。

これで実行すれば下記のような結果が得られます。

1
2
3
4
5
6
7
8
9
10
[
{
"id" : 1,
"name" : "YoshinoriN"
},
{
"id" : 2,
"name" : "Hoge"
}
]

ちなみに空の配列に対してasJsonでエンコードした場合は空配列のJSON[]が返ってくるので何か特別な例外処理的なのは必要ないです。

おわり。