Both Data.Aeson.Generic, Data.Aeson.TH and the GHC Generic code encode types with a single unary constructor like:
data T = C Int
using the encoding of the argument of the constructor. For example:
> toJSON (C 1)
It can also be converted back:
> fromJSON (toJSON (C1 1)) :: Result T
Success (C1 1)
Lets try to encode it:
> encode (toJSON (C1 1))
Chunk "1" Empty
That works. Now lets try to decode this encoded value:
> decode (encode (toJSON (C1 1))) :: Maybe T
??? I would have expected to get Just (C 1).
Just (C 1)
Of course the reason this is happening is because decode only decodes a top-level JSON value which must be either an object or an array, per RFC 4627.
The question is should we change the encoding to go to a one element array instread? Bryan, what do you think?
After thinking about this some more I think we should leave it as it is.
Because if, instead of the T type, we would have an Int the same thing would happen:
> decode (encode (toJSON 1)) :: Maybe Int
We could ask ourselves whether encode should fail on non top-level JSON values. Or maybe we could have a safeEncode function:
safeEncode :: ToJSON a => a -> Maybe ByteString
safeEncode x | topLevel v = Just $ encodeUtf8 $ toLazyText $ fromValue v
| otherwise = Nothing
v = toJSON x
topLevel :: Value -> Bool
topLevel (Object _) = True
topLevel (Array _) = True
topLevel _ = False
Describe fix for gh-63 in release notes