For a project, i need JSON representation for a org.joda.time.DateTime. For JSON, i use uPickle. As there is no implicit ReaderWriter[DateTime], i have to write it myself. After googleing around, i came up with the following code:
import com.github.nscala_time.time.Imports.DateTime
import org.joda.time.format.ISODateTimeFormat
import upickle.default._
object DateTimeRW:
val fmt = ISODateTimeFormat.dateTime()
given ReadWriter[DateTime] = readwriter[ujson.Value].bimap[DateTime](
dt => fmt.print(dt),
dtstr => fmt.parseDateTime(dtstr.str)
)
val dt = DateTime.now()
val jsonDateString = write(dt)
val dt2: DateTime = read(dt.toString)
It fails. I do not even understand the errors:
missing argument for parameter evidence$5 of method write in trait Api: (implicit evidence$5: upickle.default.Writer[org.joda.time.DateTime]): String
missing argument for parameter evidence$3 of method read in trait Api: (implicit evidence$3: upickle.default.Reader[T]): T
It seems that my implementation is wrong, but i cannot detect any syntactical error like a missing argument. Google finds NO answers for the error descriptions. Can someone help?
This compiles and works:
import com.github.nscala_time.time.Imports.DateTime
import org.joda.time.format.ISODateTimeFormat
import upickle.default._
import upickle.default.ReadWriter.join
object DateTimeRW:
val fmt = ISODateTimeFormat.dateTime()
given ReadWriter[DateTime] = readwriter[ujson.Value].bimap[DateTime](
x => fmt.print(x),
dtstr => fmt.parseDateTime(dtstr.str)
)
import DateTimeRW.given_ReadWriter_DateTime
def main(args: Array[String]): Unit = {
val dt = DateTime.now()
val jsonDateString = write(dt)
println(jsonDateString)
val dt2: DateTime = read(jsonDateString)
println(dt2)
}
sbt:
ThisBuild / version := "0.1.0-SNAPSHOT"
ThisBuild / scalaVersion := "3.4.2"
lazy val root = (project in file("."))
.settings(
name := "ScalaStuff"
)
libraryDependencies += "com.lihaoyi" %% "upickle" % "4.0.0-RC1"
libraryDependencies += "joda-time" % "joda-time" % "2.12.7"
libraryDependencies += "com.github.nscala-time" %% "nscala-time" % "2.32.0"
This one compiles and works as well (it is based on this example):
import com.github.nscala_time.time.Imports.DateTime
import org.joda.time.format.ISODateTimeFormat
import upickle.default._
import upickle.default.ReadWriter.join
//object DateTimeRW:
// val fmt = ISODateTimeFormat.dateTime()
// given ReadWriter[DateTime] = readwriter[ujson.Value].bimap[DateTime](
// x => fmt.print(x),
// dtstr => fmt.parseDateTime(dtstr.str)
// )
//import DateTimeRW.given_ReadWriter_DateTime
object DateTimeRw2:
val fmt = ISODateTimeFormat.dateTime()
implicit val rw: ReadWriter[DateTime] = upickle.default.readwriter[String].bimap[DateTime](
x => fmt.print(x),
dtAsStr => DateTime.parse(dtAsStr, fmt)
)
import DateTimeRw2.*
def main(args: Array[String]): Unit = {
val dt = DateTime.now()
val jsonDateString = write(dt)
println(jsonDateString)
val dt2: DateTime = read(jsonDateString)
println(dt2)
}
Note that I didn't have to be so explicit in my import as I've been in the other case.
Unfortunately, I have to admit, I don't know enough about the compiler to explain you why exactly in the other case you need to be explicit in importing the given (just import DateTimeRw.*
doesn't do it), and why when using the implicit val, it seems to work. I probably need to brush up my knowledge on how the compiler resolves these.
You can assign your own name if you don't like the compiler default:
object DateTimeRW:
val fmt = ISODateTimeFormat.dateTime()
given rw: ReadWriter[DateTime] = readwriter[ujson.Value].bimap[DateTime](
x => fmt.print(x),
dtstr => fmt.parseDateTime(dtstr.str)
)
import DateTimeRW.rw
Note:
read(dt.toString)
This is incorrect. You want: read(jsonDateString)
.