Reputation: 4477
I have a struct defined as follows
type WallpaperType int
// ...
type WallpaperInfo struct {
WallpaperType WallpaperType `json:"type"`
HelpMsg string `json:"help"`
Path string `json:"path"`
ImageColor color.RGBA `json:"imageColor"`
}
Printing such a struct using
winfo := &WallpaperInfo{...}
log.Println(winfo)
log.Printf("%+v\n", winfo)
Gives something like this
&{Slideshow Wallpaper is a slideshow D:\Images\Wallpapers\autumn-autumn-leaves-blur-close-up-589840.jpg {219 77 66 167}}
&{WallpaperType:Slideshow HelpMsg:Wallpaper is a slideshow Path:D:\Images\Wallpapers\autumn-autumn-leaves-blur-close-up-589840.jpg ImageColor:{R:219 G:77 B:66 A:167}}
I'd like to print it as a JSON so I've implemented the String
method for the struct as follows
func (w WallpaperInfo) String() string {
bytes, err := json.Marshal(w)
if err != nil {
return "" // ???
// this will call the method recursively
// return fmt.Sprintf("%+v\n", w)
}
return string(bytes)
}
In case there's an error in the String()
method,
I'd like to print the original &{WallpaperType:Slideshow HelpMsg:Wallpaper is a slideshow Path:D:\Images\Wallpapers\autumn-autumn-leaves-blur-close-up-589840.jpg ImageColor:{R:219 G:77 B:66 A:167}}
I've tried returning fmt.Sprintf("%+v\n", w)
but it does recursive call to the same function.
Any way I can return the original struct format? Because if json fails I don't know a way to print it differently.
Upvotes: 1
Views: 76
Reputation: 417402
Create a new type with WallpaperInfo
as its underlying type, and convert the value before passing it to fmt.Sprintf()
. Creating a new type will strip it from all its methods, including the String()
method:
func (w WallpaperInfo) String() string {
bytes, err := json.Marshal(w)
if err != nil {
type wi WallpaperInfo
return fmt.Sprintf("%+v\n", wi(w))
}
return string(bytes)
}
Although your type can never return JSON marshaling error, but in the general case this is how you can achieve what you want.
Here's an example that fails JSON marshaling on purpose, and will fall back to original struct string representation:
type fail int
func (fail) MarshalJSON() ([]byte, error) {
return nil, errors.New("on-purpose error")
}
type MyStruct struct {
F fail
}
func (m MyStruct) String() string {
bytes, err := json.Marshal(m)
if err != nil {
log.Printf("JSON error: %v", err)
type ms MyStruct
return fmt.Sprintf("%+v\n", ms(m))
}
return string(bytes)
}
Testing it:
s := MyStruct{}
log.Println(s)
log.Printf("%+v\n", s)
Which will output (try it on the Go Playground):
2009/11/10 23:00:00 JSON error: json: error calling MarshalJSON for type main.fail: on-purpose error
2009/11/10 23:00:00 {F:0}
2009/11/10 23:00:00 JSON error: json: error calling MarshalJSON for type main.fail: on-purpose error
2009/11/10 23:00:00 {F:0}
See related question:
Call json.Unmarshal inside UnmarshalJSON function without causing stack overflow
Upvotes: 2