我使用Salat库将case类序列化为mongoDb对象。我的Item.scala文件如下所示:
case class Item(_id: String = (new ObjectId).toString, itemId: Int, var name: String, var active: Boolean) extends WithId {
override def id: ObjectId = new ObjectId(_id)
}
object Item extends MongoDb[Item] with MongoDao[Item] {
override def collectionName: String = "items"
}
object ItemJsonProtocol extends DefaultJsonProtocol {
implicit val itemFormat = jsonFormat4(Item.apply)
}
现在,我使用它通过Spray HTTP将Item实体发布为Json。我想按如下方式调用它:
curl.exe -H "Content-Type: application/json" -X PUT -d "{\"itemId\":
1, \"active\":true, \"name\" : \"test\"}" http://localhost:8080/items/
希望如果我不提供,我会提供生成的ID。
然而,在调用curl命令后,我收到错误:
请求内容格式错误: 对象缺少必需的成员' _id'
有没有办法将_id字段标记为可选而不使其中的Option(此字段将始终设置)并定义自定义JsonFormat因此(de)自行序列化对象?
我已经阅读了这篇文章:https://stackoverflow.com/a/10820293/1042869,但我想知道是否还有其他办法可以做到这一点,因为我收到了许多_id字段。还有一条评论说"你可以在案例类定义中给该字段一个默认值,所以如果字段不在json中,它会为它分配默认值。",但正如你在这里看到的那样,它似乎无法发挥作用。
最佳, 马尔钦
答案 0 :(得分:0)
所以我通过编写自定义RootJsonFormat ::
解决了这个问题 implicit object ItemJsonFormat extends RootJsonFormat[Item] {
override def read(json: JsValue): Item = json.asJsObject.getFields("_id", "itemId", "name", "active") match {
case Seq(JsString(_id), JsNumber(itemId), JsString(name), JsBoolean(active)) => Item(_id = _id, itemId = itemId.toInt, name = name, active = active)
case Seq(JsNumber(itemId), JsString(name), JsBoolean(active)) => Item(itemId = itemId.toInt, name = name, active = active)
case _ => throw new DeserializationException("Item expected")
}
override def write(obj: Item): JsValue = JsObject(
"_id" -> JsString(obj._id),
"itemId" -> JsNumber(obj.itemId),
"name" -> JsString(obj.name),
"active" -> JsBoolean(obj.active)
)
}
它的作用基本上是它检查我们是否在json中收到了_id,如果我们这样做,那么我们会使用它来构造对象,在其他情况下保留自动生成的id字段。
另一件可能导致一些麻烦的事情,但在我看来值得一提 - 如果有人对嵌套对象有问题(&#34;非原始&#34;类型) - 我建议使用 .toJson < / strong> in write def(比如 obj.time.toJson ,其中obj.time是jodatime&#39; DateTime)和JsValue&#39; s .convertTo [T] def读取,如time = JsString(time).convertTo [DateTime] 。为了使其工作,必须为那些&#34;非原始&#34;定义隐式json格式。对象。
最佳, 马尔钦
答案 1 :(得分:0)
我会使用这个解决方案:
case class Item(_id: Option[String], itemId: Int, var name: String, var active: Boolean)
implicit object ItemJsonFormat extends RootJsonFormat[Item] {
override def read(value: JsValue) = {
val _id = fromField[Option[String]](value, "_id")
val itemId = fromField[Int](value, "itemId")
val expires = fromField[Long](value, "expires")
val name = fromField[String](value, "name")
val active = fromField[Boolean](value, "active")
Item(_id, itemId, name, active)
}
override def write(obj: Item): JsValue = JsObject(
"_id" -> JsString(obj._id),
"itemId" -> JsNumber(obj.itemId),
"name" -> JsString(obj.name),
"active" -> JsBoolean(obj.active)
)
}
优于json.asJsObject.getFields
解决方案的优势在于,您可以更好地控制在未定义ID的情况下接受的内容。失败的例子如下:
在这种情况下,匹配大小写会将指定的id解释为itemId而不会捕获错误。