scala - 使用 Casbah/Salat 定义自定义序列化 - 或者将序列化委托(delegate)给成员?

标签 scala mongodb casbah salat

我正在为一个来自 Rails 的新项目学习 Scala。我已经定义了一个将在我的许多模型中使用的类型,它基本上可以被认为是“属性”的集合。它基本上只是一个 hashmap 的包装器,将其大部分职责委托(delegate)给它:

case class Description(attributes: Map[String, String]) {

  override def hashCode: Int = attributes.hashCode

  override def equals(other: Any) = other match {
    case that: Description => this.attributes == that.attributes
    case _ => false
  }
}

然后我会用Description定义一个模型类,比如:

case class Person(val name: String, val description: Description)

但是,当我将 Person 与 SalatDAO 持久化时,我最终得到的文档如下所示:

{
  name : "Russell",
  description: 
  {
    attributes: 
    {
      hair: "brown",
      favourite_color: "blue"
    }
  }
}

实际上我不需要在 description 标签中嵌套 attributes 标签——我真正想要的是:

{
  name : "Russell",
  description: 
  {
    hair: "brown",
    favourite_color: "blue"
  }
}

我没试过,但我想如果我让 Description 扩展一个 Map 而不是包含一个,我想我可以让它工作,但我宁愿不,因为 Description 不是 Map 的一种,它具有 Map 的某些行为以及它自己的我稍后会添加。组合优于继承等等。

所以我的问题是,我如何告诉 Salat(或 Casbah,实际上我有点不清楚是哪个在进行转换,因为我才刚刚开始使用它们)如何序列化和反序列化 说明类?在casbah教程中here它说:

It is also possible to create your own custom type serializers and deserializers. See Custom Serializers and Deserializers.

但是这个页面好像不存在。还是我走错了路?实际上是否有一种非常简单的方法来表明这是我想要发生的事情,注释或其他什么?或者我可以简单地将序列化以某种方式委托(delegate)给属性映射吗?

编辑:在查看了 JodaTime 转换助手的源代码后,我尝试了以下方法,但还没有成功:

import org.bson.{ BSON, Transformer }
import com.mongodb.casbah.commons.conversions.MongoConversionHelper

object RegisterCustomConversionHelpers extends Serializers
  with Deserializers {
  def apply() = {
    super.register()
  }
}

trait Serializers extends MongoConversionHelper
  with DescriptionSerializer {

  override def register() = {
    super.register()
  }
  override def unregister() = {
    super.unregister()
  }
}

trait Deserializers extends MongoConversionHelper {
  override def register() = {
    super.register()
  }
  override def unregister() = {
    super.unregister()
  }
}

trait DescriptionSerializer extends MongoConversionHelper {
  private val transformer = new Transformer {
    def transform(o: AnyRef): AnyRef = o match {
      case d: Description => d.attributes.asInstanceOf[AnyRef]
      case _ => o
    }
  }

  override def register() = {
    BSON.addEncodingHook(classOf[Description], transformer)
    super.register()
  }
}

当我调用 RegisterCustomConversionHelpers() 然后保存一个 Person 时,我没有收到任何错误,它只是没有效果,保存文档的方式与以往相同。为了我想要的,这似乎还有很多事情要做。

最佳答案

Salat 维护者在这里。

我不明白 Description 在这里作为包装器的值(value)。它包装了一个属性映射,覆盖了一个 case 类的默认 equals 和 hashcode impl——这似乎是不必要的,因为无论如何 impl 被委托(delegate)给了映射,而这正是 case 类所做的——并引入了一个额外的间接层序列化对象。

您是否考虑过:

case class Person(val name: String, val description: Map[String, String])

这将完全满足您的需求。

在另一种情况下,我会推荐一个简单的类型别名,但不幸的是,Salat 目前无法支持类型别名,因为它们在 pickled Scala 签名中的描述方式存在一些问题。

(您可能出于简洁的考虑从您的示例中省略了这一点,但是您的 Mongo 模型最好有一个 _id 字段 - 如果您没有,Mongo Java 驱动程序将为您提供一个)

salat-core 测试包中有一个自定义 BSON Hook 的工作示例(它处理 java.net.URL)。可能是因为您没有在正确的位置注册它,所以您的钩子(Hook)无法正常工作?但是,我仍然建议去掉 Description,除非它添加了一些在上面的示例中不明显的值。

关于scala - 使用 Casbah/Salat 定义自定义序列化 - 或者将序列化委托(delegate)给成员?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9531846/

相关文章:

java - Play Framework 2.1 中 View 的相对时间

scala - 使用 Akka 以编程方式获取临时端口

javascript - 为什么Alert De [Fine] D,然后两行之后,不是( meteor )?

c# - 如何将 BsonDocument 对象反序列化回类

routing - 如何使用 Spray Routing 测试自定义 Json 对象

scala - Spark 流 (Spark 1.6) 与结构化流 (Spark 2.2)

scala - 出现错误 JsValue Expected 但 JsNode supplied

PHP:$this->something->($this->foo)->bar 合法吗?

scala - MongoDB Casbah 查询字段不存在或特定值

scala - Play2 + 卡斯巴 : How to provide an implicit Writes for ObjectId