简体   繁体   English

Scala:使用 circe.io 解码 Any[] 数组

[英]Scala: decode Any[] array using circe.io

I have a Java server creating a message looking like this:我有一个 Java 服务器创建一条如下所示的消息:

@SerializedName("message")
private String _message;

@SerializedName("args")
private Object[] _args;

Now in my Scala.js application, I want to deserialize this message using something like:现在在我的 Scala.js 应用程序中,我想使用以下内容反序列化此消息:

case class Notification(message: String, args: String*)

implicit val messageDecoder: Decoder[Notification] = (c: HCursor) => {
  for {
    message  <- c.downField("message").as[String]
    args     <- c.downField("args").as[List[java.lang.Object]].map(_.toString)
  } yield {
    Notification(level, message, args)
  }
}

However, Scala refuses to decode this with the error:但是,Scala 拒绝使用以下错误对其进行解码:

implicit error;
[error] !I d: Decoder[List[Object]]
[error] Decoder.importedDecoder invalid because
[error] !I exported: Exported[Decoder[List[Object]]]
[error] Decoder.decodeCanBuildFrom invalid because
[error] !I d: Decoder[Object]
[error] ??Decoder.importedDecoder invalid because
[error]   !I exported: Exported[Decoder[Object]]
[error]
[error] Decoder.decodeList invalid because
[error] !I evidence$2: Decoder[Object]
[error] ??Decoder.importedDecoder invalid because
[error]   !I exported: Exported[Decoder[Object]]
[error]       args       <- 
        c.downField("args").as[List[Object]].map(_.toString)
[error]                                           ^
[error] one error found

Any ideas on how to decode this?关于如何解码这个的任何想法? I only need to call map(toString) on the result.我只需要在结果上调用map(toString)

Edit编辑

When trying to do something like this:当尝试做这样的事情时:

args <- c.downField("args").as[Array[Any]].map(_.toString)

I get the following error:我收到以下错误:

diverging implicit expansion for type io.circe.Decoder[A]
[error] starting with value decodeString in object Decoder
[error]       args       <- 
     c.downField("args").as[Array[Any]].map(_.toString)
[error]                                           ^
[error] one error found

Edit 2编辑 2

args <- c.downField("args").as[Seq[String]].map(_.toString)

Does compile, but does not succefully parse the json (Left).可以编译,但不能成功解析 json(左)。

Edit 3编辑 3

One example of the json that is sent (in this case with integers):发送的 json 的一个示例(在本例中为整数):

{
  "message" : "{0} is smaller than {1}.",
  "args" : [
    1,
    2
  ]
}

The java server could also generate a JSON looking like this: Java 服务器还可以生成如下所示的 JSON:

{
  "message" : "{0} is smaller than {1}. ({2})",
  "args" : [
    1,
    2,
    "Hello World!"
  ]
}

Adding it as another answer, so as to keep the history clean.添加它作为另一个答案,以保持历史清洁。

Basically the following code simply works with the current json value and uses it string representation.基本上,以下代码仅适用于当前的 json 值并使用它的字符串表示。

case class Notification(message: String, args: String*)

object Notification {

  implicit val anyDecoder : Decoder[Any] =  Decoder.instance(c => {
      c.focus match {
          case Some(x) => Right(x)
          case None => Left(DecodingFailure("Could not parse", List()))
      }
  })

  implicit val messageDecoder: Decoder[Notification] = Decoder.instance(c => {
    for {
      message <- c.downField("message").as[String]
      args <- c.downField("args").as[List[Any]].map(_.toString)
    } yield {
      Notification(message, args)
    }
  })

}

And the test case is测试用例是

val json = """
            {
                "message" : "Hello" ,
                "args"    : [ 2, 3.234, 4,"good", true  ]
            }
            """

println(decode[Notification](json))

Assuming your args consists of Int and String, see if this works for you假设你的 args 由 Int 和 String 组成,看看这是否适合你

case class Notification(message: String, args: String*)

object Notification {


  implicit val decodeIntOrString: Decoder[Either[Int, String]] =
    Decoder[Int].map(Left(_)).or(Decoder[String].map(Right(_)))

  implicit val messageDecoder: Decoder[Notification] = Decoder.instance(c => {
    for {
      message <- c.downField("message").as[String]
      args <- c.downField("args").as[List[Either[Int,String]]].map(_.toString)
    } yield {
      Notification(message, args)
    }
  })

}

This was the test case这是测试用例

 val json = """
            {
                "message" : "Hello" ,
                "args"    : [ 2, 3, 4,"good"  ]
            }
            """

 println(decode[Notification](json))

Also I will like to point out to the circe discussion https://github.com/circe/circe/issues/216 , which talks about the issue more or less same.另外我想指出 circe 讨论https://github.com/circe/circe/issues/216 ,它或多或少地讨论了这个问题。 I think the idiomatic circe decision seems to be the types will derive deserialisation.我认为惯用的 circe 决定似乎是类型将派生反序列化。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM