在Haskell的Aeson中省略Nothing/null字段

use*_*931 3 haskell template-haskell aeson

我有一个类型

{-# LANGUAGE DeriveGeneric   #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE MultiWayIf      #-}

import GHC.Generics
import Data.Aeson.TH
import Data.Aeson.Types

data MyJSONObject = MyJSONObject
  { name    :: String
  , ptype   :: Maybe String
  , pid     :: Maybe String
  , subject :: Maybe String
  , message :: Maybe String
  } deriving (Show, Generic)
Run Code Online (Sandbox Code Playgroud)

还有更多的Maybe String领域.我FromJSONToJSON这个TemplateHaskell功能提供

$(deriveJSON defaultOptions
  {
    omitNothingFields  = True
  , fieldLabelModifier = \f -> if
      | f == "ptype" -> "type" -- reserved keyword
      | f == "pid"   -> "id"   -- Prelude function name
      | otherwise    -> f
  } ''MyJSONObject)
Run Code Online (Sandbox Code Playgroud)

最终,程序的输出是一个JSON文档,旨在由不允许某些字段具有空值的应用程序使用,即使它确实允许这些字段不存在.换句话说,subject不存在于JSON文档中是完全正确的,但如果确实存在,则其值不能为空.我的期望是omitNothingFields可以处理这个要求,但似乎并非如此:decoded JSON仍然具有Nothing不存在的字段的值,并且encoded JSON具有null这些字段的值.前一种情况很好; 后一种情况不是,因此问题.

我误用了,还是误解了目的,omitNothingFields?如何用Nothing/ null值忽略字段?

Mat*_*zyk 8

适合我.尝试使用泛型导出而不是TH.也许这就是它.

*Main Data.Aeson> decode "{\"name\":\"str\"}" :: Maybe MyJSONObject
Just (MyJSONObject {name = "str", ptype = Nothing, pid = Nothing, subject = Nothing, message = Nothing})
*Main Data.Aeson> encode (MyJSONObject "str" Nothing Nothing Nothing Nothing)
"{\"name\":\"str\"}"
Run Code Online (Sandbox Code Playgroud)

完整的代码是

{-# LANGUAGE DeriveGeneric   #-}
import GHC.Generics
import Data.Aeson
import Data.Aeson.Types

data MyJSONObject = MyJSONObject
  { name    :: String
  , ptype   :: Maybe String
  , pid     :: Maybe String
  , subject :: Maybe String
  , message :: Maybe String
  } deriving (Show, Generic)

instance ToJSON MyJSONObject where
  toJSON = genericToJSON defaultOptions
    { omitNothingFields = True }

instance FromJSON MyJSONObject where
  parseJSON = genericParseJSON defaultOptions
    { omitNothingFields = True }
Run Code Online (Sandbox Code Playgroud)

使用GHC 8.2.1 , aeson-1.1.2.0.