如何将Text.JSON.Generic与可选的JSON字段一起使用?

时间:2013-08-09 10:10:51

标签: json haskell data-binding

是否可以将Text.JSON.Generic与包含可选字段的JSON记录类型一起使用?我希望如果我将Haskell类型声明为Maybe a,这将“正常工作”,例如:

import Text.JSON.Generic

data Record = Record {
   myMandatoryField :: Integer,
   myOptionalField :: Maybe Integer
} deriving (Eq, Show, Data, Typeable)

但这不是正确的事。

如果无法使可选字段与Text.JSON.Generic一起使用,是否有可选的Haskell-JSON数据绑定库可以使用可选字段?

3 个答案:

答案 0 :(得分:7)

这似乎是基于泛型的解析的已知问题。 Aeson遇到了同样的问题,维护人员决定弃用该功能,转而采用基于模板Haskell的策略:https://github.com/bos/aeson/issues/118

使用Aeson,您的代码看起来非常相似:

import Data.Aeson
import Data.Aeson.TH

data Record = Record {
    myMandatoryField :: Integer,
    myOptionalField :: Maybe Integer
} deriving (Eq, Show)

$(deriveJSON id ''Record)

这样,Maybe字段按预期编码和解码:

$ ghci
λ :l Main.hs
Ok, modules loaded: Main.
λ encode $ Record 5 Nothing
"{\"myOptionalField\":null,\"myMandatoryField\":5}"
λ decode it :: Maybe Record
Just (Record {myMandatoryField = 5, myOptionalField = Nothing})

UPDATE :正如评论中所提到的,Aeson HEAD中的模板Haskell可以使用null-field省略,但这还没有在Hackage上。您现在可以使用手写的FromJSON / ToJSON实例获取该行为:

instance FromJSON Record where
    parseJSON = withObject "record" $ \o -> Record
        <$> o .: "myMandatoryField"
        <*> o .:? "myOptionalField"

instance ToJSON Record where
    toJSON (Record manf optf) = object $ catMaybes
        [ ("myMandatoryField" .=) <$> pure manf
        , ("myOptionalField" .=) <$> optf ]

答案 1 :(得分:2)

您正在寻找的行为可以通过new deriveJSON :: Options -> Name -> Q [Dec] TH generator在Aeson HEAD中找到。然后,您可以在Options struct中设置, omitNothingFields = True

不确定下一个Hackage版本的时间表是什么。

答案 2 :(得分:0)

要更新J Abrahamson答案并且为了完整起见:现在可以通过导出Generic并自定义默认选项来实现该行为,如下所示:

import           GHC.Generics

data Record = Record {
  myMandatoryField :: Integer,
  myOptionalField :: Maybe Integer
} deriving (Eq, Show, Generic)

instance FromJSON Record where
    parseJSON = genericParseJSON defaultOptions { omitNothingFields  = True }