带有varargs的case类的隐式jsonFormat

mir*_*lon 5 scala akka spray spray-json

我有一个包含varargs的case类,隐含的jsonFormat如下:

import spray.json._
case class Colors(name: String*)
object MyJsonProtocol extends DefaultJsonProtocol {
  implicit val colorFormat = jsonFormat1(Colors)
}
import MyJsonProtocol._
Colors("CadetBlue").toJson
Run Code Online (Sandbox Code Playgroud)

它引发了一个错误:

error: type mismatch;
found   : Color2.type
required: Seq[String] => Color2
Note: implicit value colorFormat is not applicable here because it comes after the application point and it lacks an explicit result type
      implicit val colorFormat = jsonFormat1(Color2)
                                            ^
Run Code Online (Sandbox Code Playgroud)

我也尝试过:

implicit val colorFormat = jsonFormat1(Colors.apply)
Run Code Online (Sandbox Code Playgroud)

这导致了一个不同的(运行时!)异常:

java.lang.RuntimeException: Cannot automatically determine case class field names and order for 'Colors', please use the 'jsonFormat' overload with explicit field name specification
Run Code Online (Sandbox Code Playgroud)

下列:

implicit val colorFormat = jsonFormat(Colors, "name")
Run Code Online (Sandbox Code Playgroud)

提出了前一个错误

甚至可以使用varargs为case类定义隐式jsonFormat?

小智 8

我也遇到了这种异常,但是在我的案例中,这是由于case类中的“ val”定义(而不是作为传递的参数)。

有问题的案例类:

case class Color(name: String) {
  val code: Int = ...
}
Run Code Online (Sandbox Code Playgroud)

工作案例类:

case class Color(name: String) {
  def code: Int = ...
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,现在将在每次调用时计算“代码”。

(使用Akka Http版本-10.1.1)


4le*_*x1v 5

它应该完美地工作,可能你有一些含糊不清的含义.这非常有效:

import spray.json._, DefaultJsonProtocol._

case class Test(param: String*)
object Test {
  implicit val testFormat = jsonFormat1(Test.apply)
}
Run Code Online (Sandbox Code Playgroud)

像最佳实践建议一样,不要使用协议模式,它会导致大项目中的大隐式错误,总是在您的伴随对象中定义隐含(因为有异常情况).另一点是避免继承,这不是真正需要的.

Scala *模式只是Seq类型构造函数的糖,所以它应该seqFormat为这种情况找到(un)marshaller.

更新

它不起作用,因为Spray用于ClassManifestcopy函数中提取字段名称,但编译器不会为构造函数中带有varargs的案例类生成此函数:

case class Test(params: String*)
def man[A: ClassManifest] = implicitly[ClassManifest[A]]
man[Test].erasure.getDeclaredMethods.filter(_.getName.contains("copy"))
res4: Array[java.lang.reflect.Method] = Array()

scala> case class Test(param: String)
defined class Test

scala> man[Test].erasure.getDeclaredMethods.filter(_.getName.contains("copy"))
warning: there was one deprecation warning; re-run with -deprecation for details
res5: Array[java.lang.reflect.Method] = Array(public Test Test.copy(java.lang.String), public java.lang.String Test.copy$default$1())
Run Code Online (Sandbox Code Playgroud)

因此,您需要手动提供字段名称.BTW我之前不知道

  • @mirelon改为`jsonFormat(Test.apply _,"param")` (2认同)