I am having trouble getting Aeson to spit out objects when I use custom types as keys. Let me demonstrate:
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-}
import Data.Aeson
import qualified Data.Map.Strict as M
import qualified Data.ByteString.Lazy.Char8 as B
import GHC.Generics
data LOL = A | B | C deriving (Eq, Ord, Generic, ToJSONKey, ToJSON)
main = do
B.putStrLn $ encode $ M.fromList [(A,"b")]
B.putStrLn $ encode $ M.fromList [("A","b")]
In one case, I get an array of arrays, while in the other it's a regular object:
$ ./tojsonkey
[["A","b"]]
{"A":"b"}
Any ideas?
Take a look at the docs for ToJSONKey
. Basically, the toJSONKey :: ToJSONKeyFunction a
method handles two cases:
For the first of these, aeson
will use a proper JSON object. For the latter, it falls back to nested arrays.
So why is it choosing option two in your case? Because you are deriving ToJSONKey
and the default implementation chooses the second more general option. You can work around this problem by manually implementing ToJSONKey LOL
:
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-}
import Data.Aeson
import Data.Aeson.Types
import qualified Data.Text as T
import qualified Data.Map.Strict as M
import qualified Data.ByteString.Lazy.Char8 as B
import GHC.Generics
data LOL = A | B | C deriving (Eq, Ord, Show, Generic, ToJSON)
instance ToJSONKey LOL where
toJSONKey = toJSONKeyText (T.pack . show)
main = do
B.putStrLn $ encode $ M.fromList [(A,"b")]
B.putStrLn $ encode $ M.fromList [("A","b")]
That should give you
$ ./tojsonkey
{"A":"b"}
{"A":"b"}