Given the following case class LogMessage
:
import io.circe.{Decoder, Encoder}
import io.circe.generic.semiauto.{deriveDecoder, deriveEncoder}
import enumeratum.{CirceEnum, Enum, EnumEntry}
import io.circe.syntax._
sealed trait LogLevel extends EnumEntry
object LogLevel extends Enum[LogLevel] with CirceEnum[LogLevel] {
val values = findValues
case object Warning extends LogLevel
case object Error extends LogLevel
case object Info extends LogLevel
case object Success extends LogLevel
}
object LogMessage {
implicit val logMessageDecoder: Decoder[LogMessage] = deriveDecoder[LogMessage]
implicit val logMessageEncoder: Encoder[LogMessage] = deriveEncoder[LogMessage]
}
case class LogMessage(level: LogLevel, text: String, args: List[String], date: Long)
case class MyClass[A](obj: A)(implicit encoder: Encoder[A]) {
def message1: String = obj.asJson.toString
def message2: Option[String] = obj.asJson.asString
}
Why does this work:
val x = MyClass(LogMessage(LogLevel.Info, "test notification", Nil, 1550218866571))
x.message1 // {\n "level" : "Info",\n "text" : "test notification",\n "args" : [\n ],\n "date" : 1550218866571\n}
But this does not:
x.message2 // None
Here is a link to Scastie with this problem: link.
In circe Json
has six asX
methods that correspond to the six data types in JSON. For example, if a Json
instance x
represents a JSON boolean, x.asBoolean
will return a Some
containing the value as a Boolean
, but if x
is a JSON string, array, object, number, or null, x.asBoolean
will be empty.
You're seeing .asString
return None
in this case because you're calling it on a Json
value that represents a JSON object, not a JSON string.
The toString
method on Json
is completely different: it's the universal Scala / Java toString
, which in the case of Json
is implemented as .spaces2
. I'm not sure what you're trying to do here, but in general I'd recommend avoiding toString
—if you want to serialize an io.circe.Json
value, it's better to use a printer or the printing methods that make the formatting options more explicit (e.g. noSpaces
, spaces2
, etc.).
(For what it's worth, I'm not entirely happy with the naming of asString
, asNull
, etc. methods on Json
. In general in circe "as" is used in method names for encoding or decoding, which isn't exactly what's happening in these cases, but it's close enough that I've never bothered to come up with a better alternative.)