66 "errors"
77 "fmt"
88 "io"
9+ "reflect"
910 "sort"
1011 "strings"
1112
@@ -117,11 +118,14 @@ func (e *exportFormat) Fields() []string {
117118 return e .fields
118119}
119120
121+ // Write serializes data into JSON output written to w. If the object passed as data implements exportable,
122+ // or if data is a map or slice of exportable object, ExportData() will be called on each object to obtain
123+ // raw data for serialization.
120124func (e * exportFormat ) Write (w io.Writer , data interface {}, colorEnabled bool ) error {
121125 buf := bytes.Buffer {}
122126 encoder := json .NewEncoder (& buf )
123127 encoder .SetEscapeHTML (false )
124- if err := encoder .Encode (data ); err != nil {
128+ if err := encoder .Encode (e . exportData ( reflect . ValueOf ( data )) ); err != nil {
125129 return err
126130 }
127131
@@ -136,3 +140,44 @@ func (e *exportFormat) Write(w io.Writer, data interface{}, colorEnabled bool) e
136140 _ , err := io .Copy (w , & buf )
137141 return err
138142}
143+
144+ func (e * exportFormat ) exportData (v reflect.Value ) interface {} {
145+ switch v .Kind () {
146+ case reflect .Ptr , reflect .Interface :
147+ if ! v .IsNil () {
148+ return e .exportData (v .Elem ())
149+ }
150+ case reflect .Slice :
151+ a := make ([]interface {}, v .Len ())
152+ for i := 0 ; i < v .Len (); i ++ {
153+ a [i ] = e .exportData (v .Index (i ))
154+ }
155+ return a
156+ case reflect .Map :
157+ t := reflect .MapOf (v .Type ().Key (), emptyInterfaceType )
158+ m := reflect .MakeMapWithSize (t , v .Len ())
159+ iter := v .MapRange ()
160+ for iter .Next () {
161+ ve := reflect .ValueOf (e .exportData (iter .Value ()))
162+ m .SetMapIndex (iter .Key (), ve )
163+ }
164+ return m .Interface ()
165+ case reflect .Struct :
166+ if v .CanAddr () && reflect .PtrTo (v .Type ()).Implements (exportableType ) {
167+ ve := v .Addr ().Interface ().(exportable )
168+ return ve .ExportData (e .fields )
169+ } else if v .Type ().Implements (exportableType ) {
170+ ve := v .Interface ().(exportable )
171+ return ve .ExportData (e .fields )
172+ }
173+ }
174+ return v .Interface ()
175+ }
176+
177+ type exportable interface {
178+ ExportData ([]string ) * map [string ]interface {}
179+ }
180+
181+ var exportableType = reflect .TypeOf ((* exportable )(nil )).Elem ()
182+ var sliceOfEmptyInterface []interface {}
183+ var emptyInterfaceType = reflect .TypeOf (sliceOfEmptyInterface ).Elem ()
0 commit comments