2 votes

Dans quelle mesure puis-je demander à Aeson de faire le gros du travail ?

J'essaie d'éviter d'écrire des définitions pour toJSON. Voici l'erreur que je rencontre :

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)'

J'obtiens des erreurs similaires pour tous mes HashMap data les déclarations.

Voici le code correspondant. Faites-moi savoir s'il manque des informations.

{-# 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.

Je ne peux pas créer une instance pour Data.Aeson.Types.Class.GToJSON parce que Data.Aeson.Types.Class n'est pas exporté. Quelles sont mes options ? Que devrai-je écrire manuellement ? Est-ce que deriveJSON le meilleur choix ?

Mise à jour : J'ai mis en œuvre la suggestion ci-dessous. Voici le code

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)

La première instance donne Object fromList [("key",Array (fromList []))])

La deuxième instance donne Object fromList [("name",Array (fromList []))]

Vous savez pourquoi ? name y key sont vides ?

Comment pourrais-je le découvrir ?

Serait-il plus facile d'utiliser simplement deriveJSON .

mise à jour : Grâce à l'aide de NathanHowell, le problème le plus important a été résolu, à savoir l'instance GToJSON pour les types unaires. La solution a été de créer mes propres instances pour les types unaires. Les objets JSON sont dans le désordre, mais je ne sais pas si c'est important. Si c'est le cas, il semble qu'une autre instance ToJSON manuelle pour les champs pourrait résoudre ce problème.

mise à jour : Ok, un peu de contexte. J'écris un front-end JIRA. Je mentionne cela parce que les gens dans le futur pourraient venir ici pour découvrir la bonne nouvelle suivante : JIRA ne se soucie pas de l'ordre des objets.

4voto

Nathan Howell Points 3488

Aeson fournit un ToJSON instance pour HashMap String a . La façon la plus simple de faire fonctionner les choses est d'utiliser cette instance en convertissant le fichier HashMap les clés pour Strings . Il suffit d'un peu de langage standard pour utiliser la fonction Generic des instances pour tout le reste.

{-# 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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X