概要
同package内でのみアクセスできる(private)構造体を json.Marshal した時に戻り値が空になる。
事象
privateの構造体を用意する
pkg/User.go
package pkg
type User struct {
id string
name string
token string
}
func (u User) GetId() string {
return u.id
}
func (u User) GetName() string {
return u.name
}
func (u User) GetToken() string {
return u.token
}
func New(id, name, token string) *User {
return &User{id, name, token}
}
対象の構造体(User.go)をjson.Marshalする。
test.go
package main
import (
"encoding/json"
"fmt"
"work/pkg"
)
func main() {
user := pkg.New("0001", "test-user", "abcdefg")
fmt.Println(user)
userjson, err := json.Marshal(&user)
if err != nil {
fmt.Errorf("error marshal:", err)
}
fmt.Println(string(userjson))
}
実行結果は以下の通り、空で出力される
&{0001 test-user abcdefg}
{}
なんとなく、察してはいたけれどjson.Marshalはprivateな値は対象にしてくれない模様…
先頭文字を直してpublicにしようか迷ったがオブジェクト指向っぽく作りたかったため、今回はMarshalJSONで誤魔化す事にした。
pkg/User.go
package pkg
import "encoding/json"
type User struct {
id string
name string
token string
}
func (u User) GetId() string {
return u.id
}
func (u User) GetName() string {
return u.name
}
func (u User) GetToken() string {
return u.token
}
func New(id, name, token string) *User {
return &User{id, name, token}
}
/* json.Marshalする時に各項目をGetする処理を追加 */
func (u *User) MarshalJSON() ([]byte, error) {
v, err := json.Marshal(&struct {
Id string
Name string
Token string
}{
Id: u.GetId(),
Name: u.GetName(),
Token: u.GetToken(),
})
return v, err
}
再度、実行する
&{0001 test-user abcdefg}
{"Id":"0001","Name":"test-user","Token":"abcdefg"}
追記
Getメソッドが不要な場合もあるので、下の様なやり方でも可能。
Goの場合だとこの方がやりやすかな??
pkg/User.go
package pkg
import (
"encoding/json"
)
type User struct {
id string
name string
token string
}
func New(id, name, token string) *User {
return &User{id, name, token}
}
/* 構造体から値を取得 */
func (u *User) MarshalJSON() ([]byte, error) {
v, err := json.Marshal(&struct {
Id string
Name string
Token string
}{
Id: u.id,
Name: u.name,
Token: u.token,
})
return v, err
}
所感
値にjsonパラメータを設定する際にprivateでも取得できる様な設定方法があるのかは随時調査して行く予定です。
jsonに変換する構造体自体をpublicで作るべきなのかは、正直分からず…
もっといい実装方法をご存知の方がいらっしゃいましたら教えて頂けると幸いです。
そもそも、Goではパッケージ外部からアクセスできない構造体をprivateと読んでいいのかも謎です。
(java脳ですみません。。。)