我试图避免为toJSON编写定义。这是我遇到的错误:
Datatypes.hs:92:10:
No instance for (aeson-0.6.0.2:Data.Aeson.Types.Class.GToJSON
(GHC.Generics.Rep (HashMap Key Project)))
arising from a use of `aeson-0.6.0.2:Data.Aeson.Types.Class.$gdmtoJSON'
Possible fix:
add an instance declaration for
(aeson-0.6.0.2:Data.Aeson.Types.Class.GToJSON
(GHC.Generics.Rep (HashMap Key Project)))
In the expression:
(aeson-0.6.0.2:Data.Aeson.Types.Class.$gdmtoJSON)
In an equation for `toJSON':
toJSON = (aeson-0.6.0.2:Data.Aeson.Types.Class.$gdmtoJSON)
In the instance declaration for `ToJSON (HashMap Key Project)'
我的所有HashMap data
声明都出现了类似的错误。
以下是相关代码。如果缺少信息,请告诉我。
{-# LANGUAGE DeriveGeneric #-} -- for JTask and Fields ToJSON instances:w!
{-# LANGUAGE DeriveDataTypeable #-} -- This may be needed for HashMaps
{-# LANGUAGE FlexibleInstances #-} -- for the HashMap ToJSON instances
{-# LANGUAGE DefaultSignatures #-}
import Prelude
import Data.ByteString
import GHC.Generics (Generic )
import Data.Data
import Data.Typeable (Typeable) -- fix HashMap ToJSON instances? maybe
import Data.Aeson
import Data.Aeson.Generic
import Data.Aeson.Types -- (ToJSON,FromJSON)
import Data.HashMap.Strict (HashMap)
data JTask = JTask {fields :: Fields} deriving (Typeable,Data,Generic)
data Fields = Fields { project :: HashMap Key Project
, summary :: ByteString
, issuetype :: HashMap Name Task
, versions :: [HashMap Name Version]
, description :: ByteString
} deriving (Typeable,Data,Generic)
data Key = Key deriving (Typeable,Data,Generic)
instance Show Key where
show Key = "key"
data Name = Name deriving (Typeable,Data,Generic)
instance Show Name where
show Name = "name"
data Task = Task deriving (Typeable,Data,Generic)
type Version = ByteString -- Placeholder type. Probably using Day for realsies.
data Project = BNAP deriving (Typeable,Data,Generic) -- Fill this out as we go
instance Generic (HashMap Key Project)
instance Data (HashMap Key Project)
--instance GToJSON (HashMap Key Project)
instance Generic (HashMap Name ByteString)
instance Data (HashMap Name ByteString)
instance Generic (HashMap Name Task)
instance Data (HashMap Name Task)
-- JSON instances
instance ToJSON CreateError
instance ToJSON Fields
instance ToJSON JTask
instance ToJSON Key
instance ToJSON Name
instance ToJSON Task
instance ToJSON Project
instance ToJSON (HashMap Key Project)
instance ToJSON (HashMap Name Task)
instance ToJSON (HashMap Name ByteString)
-- instance ToJSON Version uncomment when we change Version's type.
我无法为Data.Aeson.Types.Class.GToJSON
制作实例,因为Data.Aeson.Types.Class
不会导出。我有什么选择?我需要手动编写什么? deriveJSON
是最佳选择吗?
更新: 我实施了以下建议。 这是代码
createObject :: CreateConf -> ResourceT IO Value
createObject (CreateConf iSummary iDesc dd) = do
let jfields = Fields {project = singleton Key BNAP
,summary = iSummary
,issuetype = singleton Name Task
,versions = [singleton Name (calcVersion dd)]
,description = iDesc
}
return $ toJSON (JTask jfields)
第一个实例产生Object fromList [("key",Array (fromList []))])
第二个实例产生Object fromList [("name",Array (fromList []))]
知道为什么name
和key
为空?
我怎么能找到?
使用deriveJSON
会更容易吗。
更新: 感谢NathanHowell的帮助,解决了一个更重要的问题,即一元类型的GToJSON实例。解决方案是为一元类型创建自己的实例。 JSON对象出了故障,但我不知道这是否重要。如果是这样的话,看起来Field的另一个手动ToJSON实例会修复它。
更新: 好的一点背景。我正在写一个JIRA前端。我提到这一点,因为未来的人们可能会来这里发现以下好消息:JIRA并不关心对象顺序。
答案 0 :(得分:4)
Aeson为ToJSON
提供HashMap String a
个实例。让事情变得有效的最简单方法是将HashMap
密钥转换为Strings
来使用此实例。只需轻轻一点样板文件,就可以使用Generic
个实例。
{-# LANGUAGE DeriveGeneric #-} -- for JTask and Fields ToJSON instances:w!
{-# LANGUAGE FlexibleInstances #-} -- for the HashMap ToJSON instances
{-# LANGUAGE DefaultSignatures #-}
import Prelude
import Data.ByteString
import GHC.Generics (Generic )
import Data.Aeson
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap
data JTask = JTask {fields :: Fields} deriving (Generic)
data Fields = Fields { project :: HashMap Key Project
, summary :: ByteString
, issuetype :: HashMap Name Task
, versions :: [HashMap Name Version]
, description :: ByteString
} deriving (Generic)
data Key = Key deriving (Generic)
instance Show Key where
show Key = "key"
data Name = Name deriving (Generic)
instance Show Name where
show Name = "name"
data Task = Task deriving (Generic)
type Version = ByteString -- Placeholder type. Probably using Day for realsies.
data Project = BNAP deriving (Generic) -- Fill this out as we go
instance ToJSON Fields
instance ToJSON JTask
instance ToJSON Key
instance ToJSON Name
instance ToJSON Task
instance ToJSON Project
mapfst :: (a -> b) -> [(a, v)] -> [(b, v)]
mapfst f = fmap $ \ (k, v) -> (f k, v)
instance ToJSON a => ToJSON (HashMap Key a) where
toJSON = toJSON . HashMap.fromList . mapfst show . HashMap.toList
instance ToJSON a => ToJSON (HashMap Name a) where
toJSON = toJSON . HashMap.fromList . mapfst show . HashMap.toList