2016-05-26 10 views
1

Ich habe Datentyp mit mehreren Konstrukteuren, zum BeispielWie wird der Datensatz-Summen-Datentyp in Aeson ohne Tag serialisiert?

data AB = A 
    { 
    ab :: Text 
    , a :: Text 
    } 
    | B 
    { 
    ab :: Text 
    , b :: Text 
    } deriving (Generic) 

Gerade jetzt, wenn ich Aeson verwenden A serialisiert es zu folgenden JSON generiert:

{ 
    "tag": "A", 
    "ab": "some text", 
    "a": "some text" 
} 

Ich weiß, dass es möglich ist, SumEncoding zu verwenden manipulieren, wie der Konstruktor gehandhabt wird, aber ich konnte nicht finden, was ich will.

Ist es möglich, tag Feld in serialisierten JSON irgendwie wegzulassen? Ich brauche nur eine Möglichkeit Serialisierung (kein Grund, es zu deserialisieren), aber der Datentyp ist ziemlich groß, um zu schreiben, wie man es manuell serialisiert.

Antwort

3

A hacky Weg, um die tag aus dem resultierenden Objekt löschen Sie einfach ist:

{-# LANGUAGE DeriveGeneriC#-} 
import Data.Aeson 
import Data.HashMap.Strict 
import Data.String 
import Data.Text 
import GHC.Generics 

data AB 
    = A { ab :: Text 
     , a :: Text 
     } 
    | B { ab :: Text 
     , b :: Text 
     } 
    deriving Generic 

instance ToJSON AB where 
    toJSON ab = case genericToJSON defaultOptions ab of 
    Object o -> Object (delete (fromString "tag") o) 
    _ -> error "impossible" 

Es wahrscheinlich wieder kommen werden Sie beißen, wenn die Die generische Instanz ändert sich jedoch unweigerlich. Wenn Sie dies tun, sollten Sie sich der technischen Schulden bewusst sein, die Sie ergreifen wollen.

+0

Ich denke, es ist besser, es zu nehmen und zu Aeson zu warten oder beizutragen. Dieser Hack war genau das, wonach ich suchte. Vielen Dank! – klappvisor

2

definieren Sie einfach die ToJSON Instanz selbst:

instance ToJSON AB where 
    toJSON (A ab a) = object [ "ab" .= ab, "a" .= a ] 
    toJSON (B ab a) = object [ "ab" .= ab, "a" .= a ] 

ab1 = A "foo" "bar" 
ab2 = A "abc" "def" 

*Main> import qualified Data.ByteString.Lazy.Char8 as LBS 
*Main LBS> LBS.putStrLn $ encode ab2 
{"ab":"abc","a":"def"} 
*Main LBS> LBS.putStrLn $ encode ab1 
{"ab":"foo","a":"bar"} 
+0

Ich wollte vermeiden, Code zu schreiben, um es manuell zu serialisieren aufgrund der relativ großen Anzahl von Eigenschaften (einige von ihnen 'Maybe', einige verschachtelt) und Anzahl der Konstruktoren. Aber wenn es keine andere Option gibt, werde ich mitgehen – klappvisor

+0

@klappvisor Es sollte egal sein, ob Ihre Felder geschachtelt sind oder 'Vielleicht', solange der Typ jedes Feldes eine 'ToJSON'-Instanz ist. –

+0

@DanielWagner Ich benutze 'defaultOptions {omitNothingFields = True}' also denke ich muss ich, wenn ich sie weglassen möchte – klappvisor