Encoding arbitrary types as cells

We’ve seen in a previous post how to encode collections as CSV rows. Exactly how that happened and how individual elements of the collection were turned into CSV cells was sort of glossed over, though. In this tutorial, we’ll take a deeper look at the underlying mechanism.

General mechanism

Cell encoding is type class based: kantan.csv knows how to turn a type A into a CSV cell, provided that there is an implicit instance of CellEncoder[A] in scope. All sane primitive types have default implementations

implicitly[kantan.csv.CellEncoder[Int]]
// res0: kantan.csv.package.CellEncoder[Int] = kantan.codecs.Codec$$anon$1@b13c7c6

A more complete list of default instances can be found here

And so, when asCsvWriter, writeCsv or asCsv are asked to turn a collection of elements A into a CSV row, it looks for a corresponding implicit CellEncoder and relies on it for encoding:

import kantan.csv._
import kantan.csv.ops._

List(List(1, 2, 3), List(4, 5, 6)).asCsv(rfc)
// res1: String = """1,2,3
// 4,5,6
// """

Adding support to new types

In order to add support to non-standard types, all you need to do is implement an implicit CellEncoder instance for that type. Let’s do so, for example, for Joda DateTime:

import kantan.csv._
import org.joda.time.DateTime
import org.joda.time.format.ISODateTimeFormat

implicit val jodaDateTime: CellEncoder[DateTime] = {
  val format = ISODateTimeFormat.date()
  CellEncoder.from(format.print)
}

And we can now encode collections of dates:

List(
  List(new DateTime(), new DateTime().plusDays(1)),
  List(new DateTime().plusDays(2), new DateTime().plusDays(3))
).asCsv(rfc)
// res2: String = """2022-09-06,2022-09-07
// 2022-09-08,2022-09-09
// """

If you want to learn more about:


Other tutorials: