Как сериализовать тип данных суммы записей в 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
манипулировать, как конструктор будет обрабатываться, но не смог найти то, что я хочу.
Можно ли как-то опустить tag
поле в сериализованном JSON? Мне нужен только один способ сериализации (нет причин сохранять десериализацию), но тип данных довольно большой, чтобы написать, как сериализовать его вручную.
3 ответа
Хакерский способ - просто удалить 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"
Вероятно, он вернется, чтобы укусить вас, когда родовой экземпляр неизбежно изменится, поэтому, если вы сделаете это, осознайте технический долг, который вы решили взять на себя.
Options
имеет sumEncoding
поле и defaultOptions
устанавливает это defaultTaggedObject
,
Установка его в UntaggedValue
(от SumEncoding
) следует делать то, что вы ищете.
Просто определите 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"}