Question

The newest version of Data.Aeson changed the way that ToJSON and FromJSON work for simple types like:

data Permission = Read | Write

It used to be that the generic call:

instance ToJSON Permission where 

...Would create JSON that looked like {"Read":[]} or {"Write":[]}.

But now it creates: {tag:"Read",contents:"[]"}

Which makes sense but breaks code I have written. I wrote a toJSON part by hand to give the correct looking stuff but writing the fromJSON is confusing me.

Any ideas?

Thanks

Était-ce utile?

La solution 2

Since the value contained in the Object constructor for Data.Aeson.Value is just a strict HashMap, we can extract the keys from it and make a decision based on that. I tried this and it worked pretty well.

{-# LANGUAGE OverloadedStrings #-}
module StackOverflow where

import Data.Aeson
import Control.Monad
import Data.HashMap.Strict (keys)

data Permission = Read | Write

instance FromJSON Permission where
    parseJSON (Object v) =
        let ks = keys v
        in case ks of
            ["Read"] -> return Read
            ["Write"] -> return Write
            _ -> mzero
    parseJSON _ = mzero

You can test it with decode "{\"Read\": []}" :: Maybe Permission. The mzero in parseJSON ensures that if something else is passed in, it'll just return Nothing. Since you seem to want to only check if there is a single key matching one of your two permissions, this is pretty straightforward and will properly return Nothing on all other inputs.

Autres conseils

You could control how datatype with all nullary constructors is encoded using allNullaryToStringTag field on Data.Aeson.Options. Set it to True and it will be encoded simply as string.

import Data.Aeson.Types (Options (..), defaultOptions)

data Permission = Read | Write

$(deriveToJSON (defaultOptions {allNullaryToStringTag = True}) ''Permission)

Take a look at Options definition, it contains other handy fields.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top