如何在没有标签的情况下序列化Aeson中的记录总和数据类型?

时间:2016-05-26 18:49:37

标签: json haskell aeson

我有多个构造函数的数据类型,例如

data AB = A 
  { 
    ab :: Text
  , a :: Text
  } 
  | B 
  {
    ab :: Text
  , b :: Text
  } deriving (Generic)

现在,当我使用Aeson将其生成的A序列化为跟随JSON:

{
  "tag": "A",
  "ab": "some text",
  "a": "some text"
}

我知道可以使用SumEncoding来操纵构造函数的处理方式,但无法找到我想要的内容。

是否有可能以某种方式省略序列化JSON中的tag字段?我只需要一种方式序列化(没有理由让它反序列化),但数据类型对于编写如何手动序列化来说非常重要。

3 个答案:

答案 0 :(得分:4)

Options有一个sumEncoding字段,defaultOptions将此字段设置为defaultTaggedObject

将其设置为UntaggedValue(来自SumEncoding,在aeson-1.0.0.0和更高版本中可用)应该可以满足您的需求。

答案 1 :(得分:2)

自己定义ToJSON个实例:

instance ToJSON AB where
    toJSON (A ab a) = object [ "ab" .= ab, "a" .= a ]
    toJSON (B ab a) = object [ "ab" .= ab, "a" .= a ]

ab1 = A "foo" "bar"
ab2 = A "abc" "def"

*Main> import qualified Data.ByteString.Lazy.Char8 as LBS
*Main LBS> LBS.putStrLn $ encode ab2
{"ab":"abc","a":"def"}
*Main LBS> LBS.putStrLn $ encode ab1
{"ab":"foo","a":"bar"}

答案 2 :(得分:2)

一种hacky方式是简单地从结果对象中删除tag

{-# LANGUAGE DeriveGeneric #-}
import Data.Aeson
import Data.HashMap.Strict
import Data.String
import Data.Text
import GHC.Generics

data AB
  = A { ab :: Text
      , a  :: Text
      }
  | B { ab :: Text
      , b  :: Text
      }
  deriving Generic

instance ToJSON AB where
  toJSON ab = case genericToJSON defaultOptions ab of
    Object o -> Object (delete (fromString "tag") o)
    _ -> error "impossible"

但是,当通用实例不可避免地发生变化时,它可能会回来咬你,所以如果你这样做,就要意识到你选择承担的技术债务。