packages feed

aeson 0.8.0.2 → 0.8.1.0

raw patch · 11 files changed

+301/−70 lines, 11 filesdep +transformersdep ~attoparsecdep ~bytestringdep ~unordered-containersPVP ok

version bump matches the API change (PVP)

Dependencies added: transformers

Dependency ranges changed: attoparsec, bytestring, unordered-containers

API changes (from Hackage documentation)

Files

Data/Aeson/Encode.hs view
@@ -29,10 +29,9 @@  import Data.Aeson.Types (Value(..)) import Data.Monoid (mappend)-import Data.Scientific (Scientific, coefficient, base10Exponent)+import Data.Scientific (FPFormat(..), Scientific, base10Exponent) import Data.Text.Lazy.Builder-import Data.Text.Lazy.Builder.Int (decimal)-import Data.Text.Lazy.Builder.Scientific (scientificBuilder)+import Data.Text.Lazy.Builder.Scientific (formatScientificBuilder) import Numeric (showHex) import qualified Data.HashMap.Strict as H import qualified Data.Text as T@@ -77,8 +76,6 @@         where (h,t) = {-# SCC "break" #-} T.break isEscape q     isEscape c = c == '\"' ||                  c == '\\' ||-                 c == '<'  ||-                 c == '>'  ||                  c < '\x20'     escape '\"' = "\\\""     escape '\\' = "\\\\"@@ -86,22 +83,17 @@     escape '\r' = "\\r"     escape '\t' = "\\t" -    -- The following prevents untrusted JSON strings containing </script> or -->-    -- from causing an XSS vulnerability:-    escape '<'  = "\\u003c"-    escape '>'  = "\\u003e"-     escape c         | c < '\x20' = fromString $ "\\u" ++ replicate (4 - length h) '0' ++ h         | otherwise  = singleton c         where h = showHex (fromEnum c) ""  fromScientific :: Scientific -> Builder-fromScientific s-    | e < 0     = scientificBuilder s-    | otherwise = decimal (coefficient s * 10 ^ e)+fromScientific s = formatScientificBuilder format prec s   where-    e = base10Exponent s+    (format, prec)+      | base10Exponent s < 0 = (Generic, Nothing)+      | otherwise            = (Fixed,   Just 0)  (<>) :: Builder -> Builder -> Builder (<>) = mappend
Data/Aeson/Parser/Internal.hs view
@@ -28,26 +28,31 @@     , eitherDecodeStrictWith     ) where -import Data.ByteString.Builder-  (Builder, byteString, toLazyByteString, charUtf8, word8)- import Control.Applicative ((*>), (<$>), (<*), liftA2, pure)+import Control.Monad.IO.Class (liftIO) import Data.Aeson.Types (Result(..), Value(..)) import Data.Attoparsec.ByteString.Char8 (Parser, char, endOfInput, scientific,                                          skipSpace, string) import Data.Bits ((.|.), shiftL)-import Data.ByteString (ByteString)+import Data.ByteString.Internal (ByteString(..)) import Data.Char (chr)-import Data.Monoid (mappend, mempty) import Data.Text (Text) import Data.Text.Encoding (decodeUtf8')+import Data.Text.Internal.Encoding.Utf8 (ord2, ord3, ord4)+import Data.Text.Internal.Unsafe.Char (ord) import Data.Vector as Vector (Vector, fromList) import Data.Word (Word8)+import Foreign.ForeignPtr (withForeignPtr)+import Foreign.Ptr (minusPtr)+import Foreign.Ptr (Ptr, plusPtr)+import Foreign.Storable (poke)+import System.IO.Unsafe (unsafePerformIO) import qualified Data.Attoparsec.ByteString as A import qualified Data.Attoparsec.Lazy as L import qualified Data.Attoparsec.Zepto as Z import qualified Data.ByteString as B import qualified Data.ByteString.Lazy as L+import qualified Data.ByteString.Internal as B import qualified Data.ByteString.Unsafe as B import qualified Data.HashMap.Strict as H @@ -109,7 +114,7 @@ objectValues :: Parser Text -> Parser Value -> Parser (H.HashMap Text Value) objectValues str val = do   skipSpace-  let pair = liftA2 (,) (str <* skipSpace) (char ':' *> skipSpace *> val)+  let pair = liftA2 (,) (str <* skipSpace) (char ':' *> val)   H.fromList <$> commaSeparated pair CLOSE_CURLY {-# INLINE objectValues #-} @@ -154,6 +159,7 @@ -- to preserve interoperability and security. value :: Parser Value value = do+  skipSpace   w <- A.peekWord8'   case w of     DOUBLE_QUOTE  -> A.anyWord8 *> (String <$> jstring_)@@ -169,6 +175,7 @@ -- | Strict version of 'value'. See also 'json''. value' :: Parser Value value' = do+  skipSpace   w <- A.peekWord8'   case w of     DOUBLE_QUOTE  -> do@@ -198,7 +205,7 @@                                         else Just (c == BACKSLASH)   _ <- A.word8 DOUBLE_QUOTE   s1 <- if BACKSLASH `B.elem` s-        then case Z.parse unescape s of+        then case unescape s of             Right r  -> return r             Left err -> fail err          else return s@@ -209,42 +216,55 @@  {-# INLINE jstring_ #-} -unescape :: Z.Parser ByteString-unescape = toByteString <$> go mempty where-  go acc = do+unescape :: ByteString -> Either String ByteString+unescape s = unsafePerformIO $ do+  let len = B.length s+  fp <- B.mallocByteString len+  -- We perform no bounds checking when writing to the destination+  -- string, as unescaping always makes it shorter than the source.+  withForeignPtr fp $ \ptr -> do+    ret <- Z.parseT (go ptr) s+    case ret of+      Left err -> return (Left err)+      Right p -> do+        let newlen = p `minusPtr` ptr+            slop = len - newlen+        Right <$> if slop >= 128 && slop >= len `quot` 4+                  then B.create newlen $ \np -> B.memcpy np ptr newlen+                  else return (PS fp 0 newlen)+ where+  go ptr = do     h <- Z.takeWhile (/=BACKSLASH)     let rest = do           start <- Z.take 2           let !slash = B.unsafeHead start               !t = B.unsafeIndex start 1-              escape = case B.findIndex (==t) "\"\\/ntbrfu" of+              escape = case B.elemIndex t "\"\\/ntbrfu" of                          Just i -> i                          _      -> 255           if slash /= BACKSLASH || escape == 255             then fail "invalid JSON escape sequence"-            else do-            let cont m = go (acc `mappend` byteString h `mappend` m)-                {-# INLINE cont #-}+            else             if t /= 117 -- 'u'-              then cont (word8 (B.unsafeIndex mapping escape))+              then copy h ptr >>= word8 (B.unsafeIndex mapping escape) >>= go               else do                    a <- hexQuad                    if a < 0xd800 || a > 0xdfff-                     then cont (charUtf8 (chr a))+                     then copy h ptr >>= charUtf8 (chr a) >>= go                      else do                        b <- Z.string "\\u" *> hexQuad                        if a <= 0xdbff && b >= 0xdc00 && b <= 0xdfff                          then let !c = ((a - 0xd800) `shiftL` 10) +                                        (b - 0xdc00) + 0x10000-                              in cont (charUtf8 (chr c))+                              in copy h ptr >>= charUtf8 (chr c) >>= go                          else fail "invalid UTF-16 surrogates"     done <- Z.atEnd     if done-      then return (acc `mappend` byteString h)+      then copy h ptr       else rest   mapping = "\"\\/\n\t\b\r\f" -hexQuad :: Z.Parser Int+hexQuad :: Z.ZeptoT IO Int hexQuad = do   s <- Z.take 4   let hex n | w >= C_0 && w <= C_9 = w - C_0@@ -321,6 +341,37 @@ jsonEOF' :: Parser Value jsonEOF' = json' <* skipSpace <* endOfInput -toByteString :: Builder -> ByteString-toByteString = L.toStrict . toLazyByteString-{-# INLINE toByteString #-}+word8 :: Word8 -> Ptr Word8 -> Z.ZeptoT IO (Ptr Word8)+word8 w ptr = do+  liftIO $ poke ptr w+  return $! ptr `plusPtr` 1++copy :: ByteString -> Ptr Word8 -> Z.ZeptoT IO (Ptr Word8)+copy (PS fp off len) ptr =+  liftIO . withForeignPtr fp $ \src -> do+    B.memcpy ptr (src `plusPtr` off) len+    return $! ptr `plusPtr` len++charUtf8 :: Char -> Ptr Word8 -> Z.ZeptoT IO (Ptr Word8)+charUtf8 ch ptr+  | ch < '\x80'   = liftIO $ do+                       poke ptr (fromIntegral (ord ch))+                       return $! ptr `plusPtr` 1+  | ch < '\x800'  = liftIO $ do+                       let (a,b) = ord2 ch+                       poke ptr a+                       poke (ptr `plusPtr` 1) b+                       return $! ptr `plusPtr` 2+  | ch < '\xffff' = liftIO $ do+                       let (a,b,c) = ord3 ch+                       poke ptr a+                       poke (ptr `plusPtr` 1) b+                       poke (ptr `plusPtr` 2) c+                       return $! ptr `plusPtr` 3+  | otherwise     = liftIO $ do+                       let (a,b,c,d) = ord4 ch+                       poke ptr a+                       poke (ptr `plusPtr` 1) b+                       poke (ptr `plusPtr` 2) c+                       poke (ptr `plusPtr` 3) d+                       return $! ptr `plusPtr` 4
Data/Aeson/Types/Class.hs view
@@ -129,7 +129,8 @@ -- -- An example type and instance: ----- @{-\# LANGUAGE OverloadedStrings #-}+-- @+-- {-\# LANGUAGE OverloadedStrings #-} -- -- data Coord = Coord { x :: Double, y :: Double } --@@ -165,7 +166,8 @@ -- -- For example the previous example can be simplified to just: ----- @{-\# LANGUAGE DeriveGeneric \#-}+-- @+-- {-\# LANGUAGE DeriveGeneric \#-} -- -- import GHC.Generics --
Data/Aeson/Types/Instances.hs view
@@ -64,10 +64,12 @@ import qualified Data.Scientific as Scientific (coefficient, base10Exponent, fromFloatDigits, toRealFloat) import Data.Attoparsec.Number (Number(..)) import Data.Fixed+import Data.Foldable (toList)+import Data.Functor.Identity (Identity(..)) import Data.Hashable (Hashable(..)) import Data.Int (Int8, Int16, Int32, Int64) import Data.Maybe (fromMaybe)-import Data.Monoid (Dual(..), First(..), Last(..), mappend)+import Data.Monoid (Dual(..), First(..), Last(..)) import Data.Ratio (Ratio, (%), numerator, denominator) import Data.Text (Text, pack, unpack) import Data.Time (UTCTime, ZonedTime(..), TimeZone(..))@@ -87,6 +89,7 @@ import qualified Data.IntSet as IntSet import qualified Data.Map as M import qualified Data.Set as Set+import qualified Data.Sequence as Seq import qualified Data.Tree as Tree import qualified Data.Text as T import qualified Data.Text.Lazy as LT@@ -97,6 +100,14 @@ import qualified Data.Vector.Unboxed as VU import qualified Data.Vector.Mutable as VM ( unsafeNew, unsafeWrite ) +instance (ToJSON a) => ToJSON (Identity a) where+    toJSON (Identity a) = toJSON a+    {-# INLINE toJSON #-}++instance (FromJSON a) => FromJSON (Identity a) where+    parseJSON a      = Identity <$> parseJSON a+    {-# INLINE parseJSON #-}+ instance (ToJSON a) => ToJSON (Maybe a) where     toJSON (Just a) = toJSON a     toJSON Nothing  = Null@@ -339,6 +350,14 @@     parseJSON = withArray "[a]" $ mapM parseJSON . V.toList     {-# INLINE parseJSON #-} +instance (ToJSON a) => ToJSON (Seq.Seq a) where+    toJSON = toJSON . toList+    {-# INLINE toJSON #-}++instance (FromJSON a) => FromJSON (Seq.Seq a) where+    parseJSON = withArray "Seq a" $ traverse parseJSON . Seq.fromList . V.toList+    {-# INLINE parseJSON #-}+ instance (ToJSON a) => ToJSON (Vector a) where     toJSON = Array . V.map toJSON     {-# INLINE toJSON #-}@@ -482,8 +501,11 @@           | otherwise = "%z"  formatMillis :: (FormatTime t) => t -> String-formatMillis t = take 3 . formatTime defaultTimeLocale "%q" $ t+formatMillis = take 3 . formatSubseconds +formatSubseconds :: (FormatTime t) => t -> String+formatSubseconds = formatTime defaultTimeLocale "%q"+ instance FromJSON ZonedTime where     parseJSON (String t) =       tryFormats alternateFormats@@ -495,20 +517,32 @@             Nothing -> empty         tryFormats = foldr1 (<|>) . map tryFormat         alternateFormats =-          dateTimeFmt defaultTimeLocale :-          distributeList ["%Y", "%Y-%m", "%F"]-                         ["T%R", "T%T", "T%T%Q", "T%T%QZ", "T%T%Q%z"]--        distributeList xs ys =-          foldr (\x acc -> acc ++ distribute x ys) [] xs-        distribute x = map (mappend x)+            "%FT%T%QZ" :  -- (javascript new Date().toISOString())+            "%F %T%Q%z" :   -- (postgres)+            "%F %T%Q %Z" :   -- (time's Show format)+            "%FT%T%Q%z" :+            "%Y-%mT%T%Q" :+            "%Y-%mT%R" :+            "%Y-%mT%T" :+            "%Y-%mT%T%QZ" :+            "%Y-%mT%T%Q%z" :+            "%YT%T%Q" :+            "%YT%R" :+            "%YT%T" :+            "%YT%T%QZ" :+            "%YT%T%Q%z" :+            "%FT%T%Q" :+            "%FT%R" :+            "%FT%T" :+            dateTimeFmt defaultTimeLocale :+            []      parseJSON v = typeMismatch "ZonedTime" v  instance ToJSON UTCTime where     toJSON t = String $ pack $ formatTime defaultTimeLocale format t       where-        format = "%FT%T." ++ formatMillis t ++ "Z"+        format = "%FT%T." ++ formatSubseconds t ++ "Z"     {-# INLINE toJSON #-}  instance FromJSON UTCTime where
Data/Aeson/Types/Internal.hs view
@@ -180,7 +180,7 @@            | Number !Scientific            | Bool !Bool            | Null-             deriving (Eq, Show, Typeable, Data)+             deriving (Eq, Read, Show, Typeable, Data)  -- | A newtype wrapper for 'UTCTime' that uses the same non-standard -- serialization format as Microsoft .NET, whose @System.DateTime@
aeson.cabal view
@@ -1,9 +1,9 @@ name:            aeson-version:         0.8.0.2+version:         0.8.1.0 license:         BSD3 license-file:    LICENSE category:        Text, Web, JSON-copyright:       (c) 2011-2014 Bryan O'Sullivan+copyright:       (c) 2011-2015 Bryan O'Sullivan                  (c) 2011 MailRank, Inc. author:          Bryan O'Sullivan <bos@serpentine.com> maintainer:      Bryan O'Sullivan <bos@serpentine.com>@@ -99,7 +99,7 @@     Data.Aeson.Types.Internal    build-depends:-    attoparsec >= 0.11.3.4,+    attoparsec >= 0.13.0.0,     base == 4.*,     bytestring >= 0.10.4.0,     containers,@@ -112,6 +112,7 @@     syb,     template-haskell >= 2.4,     text >= 1.1.1.0,+    transformers,     unordered-containers >= 0.2.3.0,     vector >= 0.7.1 @@ -121,7 +122,6 @@     build-depends: time >= 1.5    if flag(developer)-    ghc-options: -Werror     ghc-prof-options: -auto-all    ghc-options: -O2 -Wall@@ -151,6 +151,7 @@     bytestring,     containers,     ghc-prim >= 0.2,+    old-locale,     template-haskell,     test-framework,     test-framework-hunit,
benchmarks/aeson-benchmarks.cabal view
@@ -2,17 +2,70 @@ version:             0 build-type:          Simple -cabal-version:       >=1.2+cabal-version:       >=1.8 +flag old-locale+  description: If false then depend on time >= 1.5.+               .+               If true then depend on time < 1.5 together with old-locale.+  default: False++library+  hs-source-dirs: ..++  exposed-modules:+    Data.Aeson+    Data.Aeson.Encode+    Data.Aeson.Generic+    Data.Aeson.Parser+    Data.Aeson.Types+    Data.Aeson.TH++  other-modules:+    Data.Aeson.Encode.ByteString+    Data.Aeson.Functions+    Data.Aeson.Parser.Internal+    Data.Aeson.Types.Class+    Data.Aeson.Types.Generic+    Data.Aeson.Types.Instances+    Data.Aeson.Types.Internal++  build-depends:+    attoparsec >= 0.13.0.0,+    base == 4.*,+    bytestring >= 0.10.4.0,+    containers,+    deepseq,+    dlist >= 0.2,+    ghc-prim >= 0.2,+    hashable >= 1.1.2.0,+    mtl,+    scientific >= 0.3.1 && < 0.4,+    syb,+    template-haskell >= 2.4,+    text >= 1.1.1.0,+    transformers,+    unordered-containers >= 0.2.3.0,+    vector >= 0.7.1++  if flag(old-locale)+    build-depends: time < 1.5, old-locale+  else+    build-depends: time >= 1.5++  ghc-options: -O2 -Wall+  cpp-options: -DGENERICS+ executable aeson-benchmark-compare-with-json   main-is: CompareWithJSON.hs   ghc-options: -Wall -O2 -rtsopts   build-depends:-    aeson,+    aeson-benchmarks,     base,     blaze-builder,     bytestring,     criterion,+    deepseq,     json,     text @@ -20,16 +73,22 @@   main-is: AesonEncode.hs   ghc-options: -Wall -O2 -rtsopts   build-depends:-    aeson,-    base+    aeson-benchmarks,+    attoparsec,+    base,+    bytestring,+    deepseq,+    time  executable aeson-benchmark-aeson-parse   main-is: AesonParse.hs   ghc-options: -Wall -O2 -rtsopts   build-depends:-    aeson,+    aeson-benchmarks,     attoparsec,-    base+    base,+    bytestring,+    time  executable aeson-benchmark-json-parse   main-is: JsonParse.hs
+ benchmarks/json-data/sigma.json view

file too large to diff

changelog.md view
@@ -1,3 +1,29 @@+0.8.1.0++* Encoding a Scientific value with a huge exponent is now handled+  efficiently.  (This would previously allocate a huge+  arbitrary-precision integer, potentially leading to a denial of+  service.)++* Handling of strings that contain backslash escape sequences is+  greatly improved.  For a pathological string containing almost a+  megabyte of consecutive backslashes, the new implementation is 27x+  faster and uses 42x less memory.++* The ToJSON instance for UTCTime is rendered with higher (picosecond)+  resolution.++* The value parser now correctly handles leading whitespace.++* New instances of ToJSON and FromJSON for Data.Sequence and+  Data.Functor.Identity.  The Value type now has a Read instance.++* ZonedTime parser ordering now favours the standard JSON format,+  increasing efficiency in the common case.++* Encoding to a Text.Builder now escapes '<' and '>' characters, to+  reduce XSS risk.+ 0.8.0.2  * Fix ToJSON instance for 15-tuples (see #223).
examples/TemplateHaskell.hs view
@@ -14,10 +14,6 @@              deriving (Show)  -- This splice will derive instances of ToJSON and FromJSON for us.------ The use of "id" below is a placeholder function to transform the--- names of the type's fields.  We don't want to transform them, so we--- use the identity function.  $(deriveJSON defaultOptions ''Coord) 
tests/Properties.hs view
@@ -18,8 +18,7 @@ import qualified Data.Text.Lazy.Builder as TLB import qualified Data.Text.Lazy.Encoding as TLE import qualified Data.HashMap.Strict as H-import Data.Time.Clock (UTCTime(..))-import Data.Time (ZonedTime(..))+import Data.Time import Instances () import Types import Encoders@@ -29,9 +28,14 @@ import qualified Data.Map as Map #endif +import System.IO+import System.IO.Unsafe (unsafePerformIO)+import System.Locale  roundTripCamel :: String -> Assertion roundTripCamel name = assertEqual "" name (camelFrom '_' $ camelTo '_' name)++   where     camelFrom c s = let (p:ps) = split c s                     in concat $ p : map capitalize ps@@ -67,6 +71,71 @@                 Error _ -> False                 Success x' -> x == x' +zonedTimeToJSON :: ZonedTime -> Bool+zonedTimeToJSON t = and $+    toFromJSON' "%FT%T%QZ" t (clearTimeZone t) :  -- (javascript new Date().toISOString())+    toFromJSON' "%F %T%Q%z" t t :   -- (postgres)+    toFromJSON' "%F %T%Q %Z" t t :   -- (time's Show format)+    toFromJSON' "%FT%T%Q%z" t t :+    toFromJSON' "%Y-%mT%T%Q" t (clearTimeZone . clearDay $ t) :+    toFromJSON' "%Y-%mT%R" t (clearTimeZone . clearDay . clearSeconds $ t) :+    toFromJSON' "%Y-%mT%T" t (clearTimeZone . clearDay $ t) :+    toFromJSON' "%Y-%mT%T%QZ" t (clearTimeZone . clearDay $ t) :+    toFromJSON' "%Y-%mT%T%Q%z" t (clearDay t) :+    toFromJSON' "%YT%T%Q" t (clearTimeZone . clearMonth . clearDay $ t) :+    toFromJSON' "%YT%R" t (clearTimeZone . clearMonth . clearDay . clearSeconds $ t) :+    toFromJSON' "%YT%T" t (clearTimeZone . clearMonth . clearDay $ t) :+    toFromJSON' "%YT%T%QZ" t (clearTimeZone . clearMonth . clearDay $ t) :+    toFromJSON' "%YT%T%Q%z" t (clearMonth . clearDay $ t) :+    toFromJSON' "%FT%T%Q" t (clearTimeZone t) :+    toFromJSON' "%FT%R" t (clearTimeZone . clearSeconds $ t) :+    toFromJSON' "%FT%T" t (clearTimeZone t) :+    toFromJSON' (dateTimeFmt defaultTimeLocale) t t :+    []+  where+    toJSON' :: String -> ZonedTime -> Value+    toJSON' format = toJSON . formatTime defaultTimeLocale format++    toFromJSON' :: String -> ZonedTime -> ZonedTime -> Bool+    toFromJSON' format t_ t_' = case fromJSON . toJSON' format $ t_ of+                                  Error msg -> error' msg+                                  Success t_'' -> if t_'' == t_' then True else error' (show t_'')+      where+        error' :: String -> Bool+        error' msg = unsafePerformIO (hPutStrLn stderr . ("zonedTimeToJSON: " ++) $ show+                                       (format, t_, toJSON' format t_, t_', msg))+            `seq` False++clearTimeZone :: ZonedTime -> ZonedTime+clearTimeZone t = t { zonedTimeZone = TimeZone 0 False "" }++clearMonth :: ZonedTime -> ZonedTime+clearMonth = f+  where+    f zt = zt { zonedTimeToLocalTime = g $ zonedTimeToLocalTime zt }+    g lt = lt { localDay = h $ localDay lt }++    h :: Day -> Day+    h = maybe (error "clearMonth") id . parseTime defaultTimeLocale "%Y-%m-%d" . formatTime defaultTimeLocale "%Y-01-%d"++clearDay :: ZonedTime -> ZonedTime+clearDay = f+  where+    f zt = zt { zonedTimeToLocalTime = g $ zonedTimeToLocalTime zt }+    g lt = lt { localDay = h $ localDay lt }++    h :: Day -> Day+    h = maybe (error "clearDay") id . parseTime defaultTimeLocale "%Y-%m-%d" . formatTime defaultTimeLocale "%Y-%m-01"++clearSeconds :: ZonedTime -> ZonedTime+clearSeconds = f+  where+    f zt = zt { zonedTimeToLocalTime = g $ zonedTimeToLocalTime zt }+    g lt = lt { localTimeOfDay = h $ localTimeOfDay lt }++    h :: TimeOfDay -> TimeOfDay+    h = maybe (error "clearSeconds") id . parseTime defaultTimeLocale "%H:%M:%S" . formatTime defaultTimeLocale "%H:%M:00"+ modifyFailureProp :: String -> String -> Bool modifyFailureProp orig added =     result == Error (added ++ orig)@@ -126,14 +195,14 @@   testGroup "roundTrip" [       testProperty "Bool" $ roundTripEq True     , testProperty "Double" $ roundTripEq (1 :: Approx Double)-    , testProperty "Int" $ roundTripEq (1::Int)-    , testProperty "Integer" $ roundTripEq (1::Integer)-    , testProperty "String" $ roundTripEq (""::String)+    , testProperty "Int" $ roundTripEq (1 :: Int)+    , testProperty "Integer" $ roundTripEq (1 :: Integer)+    , testProperty "String" $ roundTripEq ("" :: String)     , testProperty "Text" $ roundTripEq T.empty-    , testProperty "Foo" $ roundTripEq (undefined::Foo)+    , testProperty "Foo" $ roundTripEq (undefined :: Foo)     , testProperty "DotNetTime" $ roundTripEq (undefined :: DotNetTime)     , testProperty "UTCTime" $ roundTripEq (undefined :: UTCTime)-    , testProperty "ZonedTime" $ roundTripEq (undefined::ZonedTime)+    , testProperty "ZonedTime" $ roundTripEq (undefined :: ZonedTime) #ifdef GHC_GENERICS     , testGroup "ghcGenerics" [         testProperty "OneConstructor" $ roundTripEq OneConstructor@@ -149,6 +218,7 @@     , testProperty "Maybe Integer" (toFromJSON :: Maybe Integer -> Bool)     , testProperty "Either Integer Double" (toFromJSON :: Either Integer Double -> Bool)     , testProperty "Either Integer Integer" (toFromJSON :: Either Integer Integer -> Bool)+    , testProperty "ZonedTime" $ zonedTimeToJSON     ],   testGroup "deprecated" deprecatedTests,   testGroup "failure messages" [