提前道歉交叉发布:我将此问题提交给喷涂用户列表,但列表似乎已经过审核,似乎没有人回家。希望SO是一个更好的场所。
我无法使用spray-json
序列化复杂数据结构。例如,一个简单的immutable.Map[String,String]
工作正常,但是immutable.Map[String,Foo]
,其中Foo
是我定义的案例类。该文档给我的印象是,我只需要为JsonFormat
定义一个Foo
,我就准备好了。
以下是一些示例代码:
import spray.json._
import DefaultJsonProtocol._
case class Foo(hi: String)
object FooProtocol extends DefaultJsonProtocol {
implicit val fooFormat: JsonFormat[Foo] = jsonFormat1(Foo)
}
import FooProtocol._
object Thing {
def toSomething = {
Map("foo" -> Foo("bar"), "baz" -> Foo("quux")).toJson
}
}
会产生以下编译器错误:
[info] Compiling 1 Scala source to C:\spraytest\target\scala-2.10\classes...
[error] C:\spraytest\src\main\scala\Foo.scala:12: Cannot find JsonWriter or JsonFormat type class for scala.collection.immutable.Map[String,Foo]
[error] Map("foo" -> Foo("bar"), "baz" -> Foo("quux")).toJson
[error] ^
[error] one error found
[error] (compile:compile) Compilation failed
[error] Total time: 5 s, completed Jun 26, 2014 11:40:26 AM
我很难过。
答案 0 :(得分:4)
将您的FooProtocol
重命名为Foo
(这将使其成为伴随对象〜>免费的隐式范围),而是简单地继承import DefaultJsonProtocol._
,例如:
import spray.json.DefaultJsonProtocol._
case class Foo(hi: String)
object Foo {
implicit val fooJson = jsonFormat1(Foo.apply)
}
现在您需要使用您的Spray路线将正确的marshallers导入范围。 Marshaller for String可以在喷射DefaultJsonProtocol中找到,Foos marshaller可以从它的伴随对象中找到,所以你唯一需要导入的是spray.httpx.SprayJsonSupport
,这应该可以解决问题。
或者你可以保留它而只是import FooProtocol
。但从设计的角度来看,这不是最好的解决方案。
<强>更新强>
如果你看一下toJson签名,你会看到它请求一个隐含的JsonWriter,它是由jsonFormat方法生成的。 Companion对象解决了这个问题,因为scala编译器将其包含在隐式解析范围内,这是一种很好的做法,可以将您的隐含信息放在那里,因为这导致您不需要进行显式导入,例如{{1} }
对于Map和String marshallers,看看DefaultJsonProtocol trait,它扩展import FooProtocol._
和BasicFormats
,它们分别有String和Map的编组器。您需要添加的唯一内容是CollectionFormats
类的自己的编组器。
<强>解决方案强>
真正的问题在于范围内的多个marshaller含义。只需导入Foo
即可访问所有标准含义(在本例中为Map和String)。当您从此特征扩展然后将其导入当前范围时,它还会导入所有标准编组。所以问题是你在范围内有多个marshallers导致scala编译器含糊不清的问题。
答案 1 :(得分:1)
AFAIK没有Map[String,_]
的默认编组。您可以尝试显式转换对象toString(Map[String,String]
可以序列化为Json)或为Map[String, Foo]
提供编组器。
答案 2 :(得分:1)
您必须创建一个对象来保存地图,然后您可以序列化该对象。
import spray.json._
import DefaultJsonProtocol._
case class Foo(hi: String)
case class Bar( something: Map[String,Foo])
object FooBarProtocol extends DefaultJsonProtocol {
implicit val fooFormat: JsonFormat[Foo] = jsonFormat1(Foo)
implicit val barFormat: JsonFormat[Bar] = jsonFormat1(Bar)
}
object Thing {
def toSomething = {
Bar(Map("foo" -> Foo("bar"), "baz" -> Foo("quux"))).toJson
}
}