带有可变参数的案例 class 的隐式 jsonFormat
Implicit jsonFormat for case class with varargs
我有一个案例 class 包含可变参数,隐含的 jsonFormat 如下:
import spray.json._
case class Colors(name: String*)
object MyJsonProtocol extends DefaultJsonProtocol {
implicit val colorFormat = jsonFormat1(Colors)
}
import MyJsonProtocol._
Colors("CadetBlue").toJson
它引发错误:
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)
^
我也试过:
implicit val colorFormat = jsonFormat1(Colors.apply)
导致不同的(运行时!)异常:
java.lang.RuntimeException: Cannot automatically determine case class field names and order for 'Colors', please use the 'jsonFormat' overload with explicit field name specification
以下:
implicit val colorFormat = jsonFormat(Colors, "name")
引发前一个错误
甚至可以为 case class 和 varargs 定义隐式 jsonFormat?
我建议您使用 name: List[String]
定义案例 class 并使用自定义应用函数创建伴生对象。您仍然可以创建像 Colors("blue", "green")
.
这样的对象
case class Colors(name: List[String])
object Colors {
def apply(name: String*): Colors = new Colors(name.toList)
def apply(names: List[String]): Colors = new Colors(names)
}
Colors("blue", "green")
它应该可以很好地工作,可能是您在隐含方面有一些歧义。这非常有效:
import spray.json._, DefaultJsonProtocol._
case class Test(param: String*)
object Test {
implicit val testFormat = jsonFormat1(Test.apply)
}
就像最佳实践建议一样,不要使用协议模式,它会导致大项目中出现大量隐式错误,请始终在伴随对象中定义隐式(因为存在异常情况)。另一点避免继承,它不是真正需要的。
Scala *
模式只是 Seq
类型构造函数的一个糖,因此它应该为这种情况找到 seqFormat
(un)marshaller。
更新
它不起作用,因为 Spray 使用 ClassManifest
从 copy
函数中提取字段名称,但编译器不会为 case 类 中的可变参数生成此函数构造函数:
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())
因此您需要手动提供字段名称。顺便说一句,我以前不知道这个
我也遇到了这个异常,但在我的例子中,这是由于案例 class 中的 'val' 定义(不是传递的参数)造成的。
有问题 案例class:
case class Color(name: String) {
val code: Int = ...
}
工作 案例class:
case class Color(name: String) {
def code: Int = ...
}
这有点不幸,因为现在每次调用都会计算 'code'。
(使用 Akka Http 版本 - 10.1.1)
我有一个案例 class 包含可变参数,隐含的 jsonFormat 如下:
import spray.json._
case class Colors(name: String*)
object MyJsonProtocol extends DefaultJsonProtocol {
implicit val colorFormat = jsonFormat1(Colors)
}
import MyJsonProtocol._
Colors("CadetBlue").toJson
它引发错误:
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)
^
我也试过:
implicit val colorFormat = jsonFormat1(Colors.apply)
导致不同的(运行时!)异常:
java.lang.RuntimeException: Cannot automatically determine case class field names and order for 'Colors', please use the 'jsonFormat' overload with explicit field name specification
以下:
implicit val colorFormat = jsonFormat(Colors, "name")
引发前一个错误
甚至可以为 case class 和 varargs 定义隐式 jsonFormat?
我建议您使用 name: List[String]
定义案例 class 并使用自定义应用函数创建伴生对象。您仍然可以创建像 Colors("blue", "green")
.
case class Colors(name: List[String])
object Colors {
def apply(name: String*): Colors = new Colors(name.toList)
def apply(names: List[String]): Colors = new Colors(names)
}
Colors("blue", "green")
它应该可以很好地工作,可能是您在隐含方面有一些歧义。这非常有效:
import spray.json._, DefaultJsonProtocol._
case class Test(param: String*)
object Test {
implicit val testFormat = jsonFormat1(Test.apply)
}
就像最佳实践建议一样,不要使用协议模式,它会导致大项目中出现大量隐式错误,请始终在伴随对象中定义隐式(因为存在异常情况)。另一点避免继承,它不是真正需要的。
Scala *
模式只是 Seq
类型构造函数的一个糖,因此它应该为这种情况找到 seqFormat
(un)marshaller。
更新
它不起作用,因为 Spray 使用 ClassManifest
从 copy
函数中提取字段名称,但编译器不会为 case 类 中的可变参数生成此函数构造函数:
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())
因此您需要手动提供字段名称。顺便说一句,我以前不知道这个
我也遇到了这个异常,但在我的例子中,这是由于案例 class 中的 'val' 定义(不是传递的参数)造成的。
有问题 案例class:
case class Color(name: String) {
val code: Int = ...
}
工作 案例class:
case class Color(name: String) {
def code: Int = ...
}
这有点不幸,因为现在每次调用都会计算 'code'。
(使用 Akka Http 版本 - 10.1.1)