在以下代码中,encoded
等于{"FooBar":[{"Bar":4},{"Baz":2}]}
。
所需的编码为{"FooBar":{"Bar":4,"Baz":2}}
。
import Data.Aeson
import Data.Aeson.Types
data Foo = FooBar Bar Baz deriving Generic
newtype Bar = Bar Integer deriving Generic
newtype Baz = Baz Integer deriving Generic
instance ToJSON Foo where
toJSON = genericToJSON options
instance ToJSON Bar where
toJSON = genericToJSON options
instance ToJSON Baz where
toJSON = genericToJSON options
options :: Options
options = defaultOptions { tagSingleConstructors = True,
sumEncoding = ObjectWithSingleField }
foo :: Foo
foo = FooBar (Bar 4) (Baz 2)
encoded = encode foo
也就是说,我希望产品类型的构造函数是键,它们的组件是对象。我与tagSingleConstructors = True
和sumEncoding = ObjectWithSingleField
非常接近,但是Aeson将Bar
和Baz
放入列表而不是对象。
Options
中的其他修饰符似乎都不相关,但我可能会遗漏某些内容。 genericToJSON
是否可以进行所需的编码?
答案 0 :(得分:1)
使用记录语法可以实现期望的结果。
在这种情况下,Aeson会将值编码为对象。
但是,在这种情况下需要两组选项,一组用于FooBar
,另一组用于Foo
和Bar
:
data Foo = FooBar { bar:: Bar, baz :: Baz} deriving Generic
data Bar = Bar Integer deriving Generic
newtype Baz = Baz Integer deriving Generic
instance ToJSON Foo where
toJSON = genericToJSON options
instance ToJSON Bar where
toJSON = genericToJSON option_nested
instance ToJSON Baz where
toJSON = genericToJSON option_nested
options :: Options
options = defaultOptions { tagSingleConstructors = True,
sumEncoding = ObjectWithSingleField,
fieldLabelModifier = \s -> (toUpper . head) s : (tail s) }
option_nested :: Options
option_nested = defaultOptions { sumEncoding = UntaggedValue }
结果:{"FooBar":{"Baz":2,"Bar":4}}"