2014-10-17 20 views
0

我使用噴與json4s,我有下面的實現來處理更新對象的放置請求...我的問題是,我第一次提取SomeObject的實例從json,但作爲一個RESTful api,我想要在URL中指定ID。因此,我必須以某種方式創建另一個與ID索引的SomeObject實例......爲此,我使用了像SomeObject(id:Long,obj:SomeObject)這樣的構造函數。它工作得很好,但實施很醜陋,而且效率低下。我能做些什麼,所以我可以以某種方式將ID粘在那裏,這樣我只創建一個SomeObject的實例?json4s對象提取與額外的數據

class ApplicationRouter extends BaseRouter { 
    val routes = 
    pathPrefix("some-path") { 
     path("destination-resource" \ IntNumber) { id => 
     entity(as[JObject]) { rawData => 
      val extractedObject = rawData.camelizeKeys.extract[SomeObject] 
      val extractedObjectWithId = SomeObject(id, extractedObject) 
      handleRequest(extractedObjectWithId) 
     } 
     } 
    } 
} 

case class SomeObject(id: Long, data: String, someValue: Double, someDate: DateTime) { 
    def this(data: String, someValue: Double, someDate: DateTime) = this(0, data, someValue, someDate) 
    def this(id: Long, obj: SomeObject) = this(id, obj.data, obj.someValue, obj.someDate) 
} 

回答

1

我想出了一個解決這個通過文檔一段時間周圍挖後:

class ApplicationRouter extends BaseRouter { 
    val routes = 
    pathPrefix("some-path") { 
     path("destination-resource" \ IntNumber) { id => 
     entity(as[JObject]) { rawData => 
      val extractedObject = rawData.camelizeKeys.merge { 
       ("id", id) 
      }.extract[SomeObject] 
      handleRequest(extractedObject) 
     } 
     } 
    } 
} 
-1

我不知道效率,但你可以讓你的代碼「不太醜陋」通過定義SomeObjectBuilder,給你提取您的JSON值。

case class SomeObjectBuilder(data: String, someValue: Double, someDate: DateTime) { 
    def setId(id: Long) = SomeObject(id, data, someValue, someDate) 
} 

case class SomeObject(id: Long, data: String, someValue: Double, someDate: DateTime) 

隨着提取:

class ApplicationRouter extends BaseRouter { 
    val routes = 
    pathPrefix("some-path") { 
     path("destination-resource" \ IntNumber) { id => 
     entity(as[JObject]) { rawData => 
      val extractedObject = rawData.camelizeKeys.extract[SomeObjectBuilder] 
      val extractedObjectWithId = extractedObject.setId(id) 
      handleRequest(extractedObjectWithId) 
     } 
     } 
    } 
} 

這樣,你不使用默認的id設置爲零,也就是,如果我理解正確的話,從來不正確的。將其設置爲零的唯一原因是該值不被提取器知道,因此,使用構建器可以明確地實現部分實例化。

+0

我真的不能想象比這更好的解決方案(雖然我不會用SETID函數名那裏),但它仍然感覺不對。我希望有一些方法可以讓scala將一個case類提取到一個元組中,然後讓scala將該元組的參數作爲函數的參數傳遞。所以它出來像 'SomeObject(ID,someObject.toTuple.asParams)' 然後斯卡拉將使用編譯宏來提取參數,因此它實際上讀取,像 'SomeObject(ID,someObject.toTuple ._1,someObject.toTuple._2,someObject.toTuple._3)'哦。 – JBarber 2014-10-18 18:54:01

+0

由於您的ID在解壓縮之前已知,您還可以定義一個自定義解串器。這是通過擴展'CustomSerializer'完成的,後者採用描述反序列化的部分函數。你提到的「元組」聽起來很像提供'id'作爲這個部分函數的閉包。但是,在我看來,實現一個自定義序列化器會使代碼比手動設置'id'更復雜。 – 2014-10-19 03:16:04

0

由於id字段未在所有實例上設置,因此這意味着它是可選的,因此請使用Option類型來指示它。用id: Option[Long]字段定義您的案例類。這使json解析器在缺少id字段時可以跳過,但可以在您擁有時指定值。

case class SomeObject(id: Option[Long], data: String, someValue: Double, someDate: DateTime) 

class ApplicationRouter extends BaseRouter { 
    val routes = 
    pathPrefix("some-path") { 
     path("destination-resource" \ IntNumber) { id => 
     entity(as[JObject]) { rawData => 
      val extractedObject = rawData.camelizeKeys.extract[SomeObject] 
      val extractedObjectWithId = extractedObject.copy(id = Some(id)) 
      handleRequest(extractedObjectWithId) 
     } 
     } 
    } 
} 

並且不用擔心創建新對象的性能影響。它可能會比您想象的要少得多。在改進之前應該測量性能。

+0

如果我沒有弄錯,該ID不是可選的,但不存在於JSON值中,因爲它來自不同的來源:URL。換句話說,使'id'可選將在語義上是錯誤的。 – 2014-10-21 12:48:00