2012-03-02 89 views
3

我正在學習Scala,以獲得來自Rails的新項目。我已經定義了一個類型,這個類型將被用在我可以基本上被認爲是'屬性'集合的許多模型中。它基本上只是一個HashMap中的包裝,代表大部分的責任吧:當我用Casbah/Salat定義自定義序列化 - 或委託序列化成員?

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

但是:

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,像堅持用SalatDAO我結束了一個文件,看起來像這樣一個Person

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

當實際上我不需要012的嵌套在description標籤標籤 - 什麼其實我是想是這樣的:

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

我沒有試過,但我想我能得到那個工作,如果我做了Description延長Map而不是包含一個,但我'd寧可不是,因爲Description不是Map的一種類型,它的某些行爲有一些Map以及我將在稍後添加的其他行爲。繼承等構成。

所以我的問題是,我怎麼能告訴薩拉特(或卡斯巴,實際上,我有點不清楚哪個是做轉換,因爲我已經只使用它們剛剛開始)如何序列化和反序列化Description類?在卡斯巴教程here它說:

也可以創建自己的自定義類型的序列化和反序列化 。請參閱自定義序列化器和解串器。

但是這個頁面似乎並不存在。或者我是否以錯誤的方式去做?實際上是否有一種非常簡單的方式來表明這是我想要發生的事情,一個註釋還是什麼?或者我可以簡單地以某種方式將序列化委派給屬性映射?

編輯:具有看看來源爲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我沒有收到任何錯誤,它只是沒有效果,以前所未有的方式保存文檔。這似乎也相當多,必須做我想要的。

回答

4

薩拉特維護者在這裏。

我不明白描述的價值作爲一個包裝在這裏。它包裝了一個屬性映射,覆蓋了case類的默認equals和hashcode impl - 這似乎是不必要的,因爲impl無論如何委託給映射,而且正是case類所做的 - 而且還引入了一個額外的間接層序列化的對象。

你剛認爲:

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

這將不正是你想要的盒子的東西。

在另一種情況下,我會推薦一個簡單的類型別名可惜薩拉特不能因爲與他們是如何在醃製斯卡拉簽名描繪的一些問題,支持類型別名現在。

(你可能忽略該從你的簡潔的例子,但它是最好的做法爲您蒙戈模型有一個_id領域 - 如果你不這樣做,蒙戈Java驅動程序會爲您提供一個)

在salat-core測試包(它處理java.net.URL)中有一個自定義BSON掛鉤的工作示例。這可能是因爲你沒有在正確的地方註冊它而導致你的鉤子不能正常工作?但是,我仍然建議擺脫描述,除非它增加了一些在上面的示例中不明顯的值。

+0

嗨@prasinous,感謝您的回答(並感謝您在Salat上的工作!)。我爲'Description'創建了一個單獨的類的原因是我打算向它添加行爲。我可能還會在未來增加或改變其構成。 – Russell 2012-03-02 13:39:15

+0

(是的,'_id'略去了) – Russell 2012-03-02 13:41:07

+0

鑑於你說過和看測試代碼表明,它可能很難確定哪些特定的地圖需要進行反序列化到'Description'對象,我已經決定稍微改變我的設計,並將其發佈在下面的答案中。再次感謝。 – Russell 2012-03-02 17:05:08

0

基於@prasinous的回答,我決定這是不會那麼容易,所以我已經改變了我的設計有點以下,這幾乎讓我我想要的。而不是持續的Description作爲場我堅持然後香草地圖在Described性狀我想有描述,其被創建對象時在地圖上自動轉換到Description模型類混合。如果有人能夠指出任何明顯的問題或任何改進建議,將不勝感激。

class Description(val attributes: Map[String, String]){ 
    //rest of class omitted 
} 

trait Described { 
    val attributes: Map[String, String] 
    val description = new Description(attributes) 
} 

case class Person(name: String, attributes: Map[String, String]) extends Described 
+0

我正在建議「case class Person(name:String,@Key(」description「)private val attributes:Map [String,String]){lazy val description = Description(attributes)}」 – prasinous 2012-03-02 23:21:22

+0

是的,這有點簡單。我不確定我是否需要以同質方式處理不同的「描述」對象。如果沒有,我會採取這種方法。再次感謝。 – Russell 2012-03-03 10:18:01