我们可以使用TemplateHaskell
来解决这个问题。我们可以使用特定的键值映射,而不是编写ToJSON
和FromJSON
。
首先,我们必须为字段构造一个名称,该名称不是类型,例如:
data Owner = Owner {
id :: Int,
gravatar_id :: Text,
login :: Text,
avatar_url :: Text,
events_url :: URL,
followers_url :: URL,
following_url :: URL,
gists_url :: URL,
html_url :: URL,
organizations_url :: URL,
received_events_url :: URL,
repos_url :: URL,
starred_url :: URL,
subscriptions_url :: URL,
url :: URL,
<b>owner_type</b> :: Text,
site_admin :: Bool
} deriving (Generic, Show)
现在我们可以使用deriveJSON :: Options -> Name -> Q [Dec]
函数,它将构建一个fromJSON
和toJSON
实例。
关键在于Options
参数:它包含一个fieldLabelModifier :: String -> String
字段,可以重写字段名称并映射到JSON中的键。因此,我们可以在这里生成一个函数来重命名它们。
所以我们首先构造一个ownerFieldRename :: String -> String
函数:
ownerFieldRename :: String -> String
ownerFieldRename "owner_type" = "type"
ownerFieldRename name = name
这个函数作为一个身份函数,除了将"owner_type"
映射到"type"
以外。
现在我们可以使用自定义选项调用deriveJSON
函数,例如:
$(deriveJSON defaultOptions {fieldLabelModifier = ownerFieldRename} ''Owner)
全文如下:
RenameUtils.hs
:
<b>module RenameUtils where
ownerFieldRename :: String -> String
ownerFieldRename "owner_type" = "type"
ownerFieldRename name = name</b>
MainFile.hs
:
<b>{-# LANGUAGE TemplateHaskell #-}</b>
{-# LANGUAGE DeriveGeneric #-}
<b>import Data.Aeson.TH(deriveJSON, defaultOptions, Options(fieldLabelModifier))</b>
<b>import RenameUtils(ownerFieldRename)</b>
import Data.Text (Text)
type URL = Text
data Owner = Owner {
id :: Int,
gravatar_id :: Text,
login :: Text,
avatar_url :: Text,
events_url :: URL,
followers_url :: URL,
following_url :: URL,
gists_url :: URL,
html_url :: URL,
organizations_url :: URL,
received_events_url :: URL,
repos_url :: URL,
starred_url :: URL,
subscriptions_url :: URL,
url :: URL,
<b>owner_type</b> :: Text,
site_admin :: Bool
} deriving (Show)
<b>$(deriveJSON defaultOptions {fieldLabelModifier = ownerFieldRename} ''Owner)</b>
现在我们获得一个JSON对象,其中type
是键:
Prelude Main Data.Aeson> encode (Owner 1 "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" True)
"{\"id\":1,\"gravatar_id\":\"\",\"login\":\"\",\"avatar_url\":\"\",\"events_url\":\"\",\"followers_url\":\"\",\"following_url\":\"\",\"gists_url\":\"\",\"html_url\":\"\",\"organizations_url\":\"\",\"received_events_url\":\"\",\"repos_url\":\"\",\"starred_url\":\"\",\"subscriptions_url\":\"\",\"url\":\"\",\"type\":\"\",\"site_admin\":true}"
对于一个简单的fieldLabelModifier
函数,我们不需要编写一个特定的函数(我们必须在特定模块中定义),我们也可以在这里使用一个lambda表达式:
MainFile.hs
:
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE DeriveGeneric #-}
import Data.Aeson.TH(deriveJSON, defaultOptions, Options(fieldLabelModifier))
import Data.Text (Text)
type URL = Text
data Owner = Owner {
id :: Int,
gravatar_id :: Text,
login :: Text,
avatar_url :: Text,
events_url :: URL,
followers_url :: URL,
following_url :: URL,
gists_url :: URL,
html_url :: URL,
organizations_url :: URL,
received_events_url :: URL,
repos_url :: URL,
starred_url :: URL,
subscriptions_url :: URL,
url :: URL,
<b>owner_type</b> :: Text,
site_admin :: Bool
} deriving (Show)
$(deriveJSON defaultOptions {fieldLabelModifier = <b>\x -> if x == "owner_type" then "type" else x</b>} ''Owner)
ToJSON
和FromJSON
,从而进行“键转换”。 - Willem Van Onsem