0

为交叉发帖提前致歉:我将这个问题提交给了喷子用户列表,但该列表似乎已被审核,并且似乎没有人在家。希望 SO 是一个更好的场所。

我很难用spray-json. 例如,一个简单的immutable.Map[String,String]工作正常,但一个immutable.Map[String,Foo], where Foois 我定义的案例类没有。文档给我留下的印象是我只需要定义一个JsonFormatforFoo就可以了。

这是一些示例代码:

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

我难住了。

4

3 回答 3

4

将您的重命名FooProtocolFoo(这将使其成为伴随对象〜>免费的隐式范围),而不是简单地继承import DefaultJsonProtocol._,例如:

import spray.json.DefaultJsonProtocol._
case class Foo(hi: String)
object Foo {
  implicit val fooJson = jsonFormat1(Foo.apply)
}

现在您需要使用您的 Spray 路线将正确的编组器导入范围。字符串的 Marshaller 可以在 Spray DefaultJsonProtocol 中找到,而 Foos marshaller 可以从它的伴随对象中找到,所以你唯一需要导入的是spray.httpx.SprayJsonSupport,这应该可以解决问题。

或者你可以保持原样,并且只是import FooProtocol. 但从设计的角度来看,这并不是最好的解决方案。

更新

如果你看一下 toJson 签名,你会发现它请求一个隐式的 JsonWriter,它是由 jsonFormat 方法生成的。Companion 对象解决了这个问题,因为 scala 编译器将它包含在隐式解析范围中,这是一个很好的做法,将你的暗示放在那里,因为在这个原因你不需要显式导入,比如import FooProtocol._

至于 Map 和 String 编组器,请看一下 DefaultJsonProtocol trait,它扩展了BasicFormatsCollectionFormats,分别为 String 和 Map 提供了编组器。您唯一需要添加的是您自己的Foo类编组器。

解决方案

真正的问题在于范围内的多个编组器隐含。所有标准隐式(在本例中为 Map 和 String)都可以通过DefaultJsonProtocol. 当您从该特征扩展然后将其导入当前范围时,它还会导入所有标准编组器。所以问题是您在范围内有多个编组器,这导致 scala 编译器的隐含含糊不清。

于 2014-06-26T16:19:13.433 回答
1

AFAIK 没有默认编组Map[String,_]。您可以尝试将对象显式转换Map[String,String]为字符串(可以序列化为 Json),也可以为Map[String, Foo].

于 2014-06-26T16:16:49.120 回答
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
  }
}
于 2014-06-26T16:30:50.713 回答