2016-02-20 33 views
2

我使用Argonaut從遠程JSON提供者分析對象。該API有兩種類型的端點,一種是URL上的傳統REST請求以及單個JSON對象的響應。我能夠在這種類型的端點上輕鬆地使用Argonaut解析複雜的JSON返回對象。用Argonaut解析JSON流

我的問題是提供者的流式端點,它從給定端點的有界JSON對象集返回隨機JSON對象。這些對象按照它們在網站上出現的順序返回,並且可以隨時返回大約二十個不同對象中的任何一個。

通過API工作,我找不到使用Argonaut來處理這個問題的方法。這些API似乎都需要類型參數化,這在下一個對象的類型無法預測的環境中很難實現。一種選擇是根據每個JSON塊中的前幾個字符分派到不同的編解碼器,但這會破壞將JSON字符串發送到解析器並獲取對象的目標。

我已經能夠迄今爲止找到的最好的是讓所有的頂級case類的擴展空trait

implicit def ModelDecodeJson: DecodeJson[Model] = 
    DecodeJson(c => 
    c.as[ModelSubclassA].asInstanceOf[DecodeResult[Model]] 
     ||| c.as[ModelSubclassB].asInstanceOf[DecodeResult[Model]] 
     // many more here! 
) 

不幸的是,ModelSubclassAModelSubclassB都有若干關聯到其他case類,並且在編譯這個示例時,在運行時嘗試解析這些子類型時失敗。總而言之,將會有幾十個case類構成返回數據的層次結構。

我也試過用for理解構建這個,但是沒有運氣。

任何人都可以在這裏建議更好的模式?

UPDATE

下似乎有更多的可擴展的模式,但類型不會合作:

implicit def ModelDecodeJson: DecodeJson[Model] = 
    DecodeJson(c => 
    (c.as[ModelSubclassA] ||| c.as[ModelSubclassB]).asInstanceOf[DecodeResult[Model]] 
) 

Error:(10, 17) type mismatch; found : argonaut.DecodeResult[ModelSubclassB] required: argonaut.DecodeResult[Product with Serializable with Model] Note: ModelSubclassB <: Product with Serializable with Model, but class DecodeResult is invariant in type A. You may wish to define A as +A instead. (SLS 4.5) ||| c.as[ModelSubclassB]).asInstanceOf[DecodeResult[Model]] ^

所以我開始尋找在源和實現的定義DecodeResult已更改爲包含+A,如版本6.2-M1中的錯誤所示。不幸的是,升級到該版本時,所有Model子類編解碼器都變成了含糊不清的含義,這很有意義。

啊...

回答

0

這個問題的答案需要兩個部分:

  1. 「總和類型」封裝值和距離被用於返回值從類型的編解碼器。在上面的例子中,編解碼器使用Model特徵來解決隱含問題。如果它也用作返回類型,則引入遞歸定義,即編譯器無法明確解析。

  2. 一旦使用了總和類型,客戶端很容易接受這些類型,並使用match中的提取器來達到其中的實際值。