JSON

JSON #

値を JSON にエンコードする #

package main

import (
	"encoding/json"
	"fmt"
)

type User struct {
	Name string
	Age  int
}

func main() {
	// 構造体から JSON
	u := User{Name: "User1", Age: 20}
	data, err := json.Marshal(u)
	fmt.Println(string(data), err) // == {"Name":"User1","Age":20} <nil>

	// スライスから JSON
	s := []string{"foo", "bar", "buz"}
	data, err = json.Marshal(s)
	fmt.Println(string(data), err) // == ["foo","bar","buz"] <nil>

	// マップから JSON
	m := map[string]string{
		"key1": "val1",
		"key2": "val2",
		"key3": "val3",
	}
	data, err = json.Marshal(m)
	fmt.Println(string(data), err) // == {"key1":"val1","key2":"val2","key3":"val3"} <nil>
}

play_circleRun open_in_newRun In The Playground

参考ドキュメント: encoding/json

JSON から値へデコードする #

package main

import (
	"encoding/json"
	"fmt"
)

type User struct {
	Name string
	Age  int
}

func main() {
	// JSON から構造体
	data := []byte(`{"Name":"User1","Age":20}`)
	u := new(User)
	if err := json.Unmarshal(data, u); err != nil {
		panic(err)
	}
	fmt.Printf("%#v \n", u) // == &main.User{Name:"User1", Age:20}

	// JSON からスライス
	data = []byte(`["foo","bar","buz"]`)
	s := []string{}
	if err := json.Unmarshal(data, &s); err != nil {
		panic(err)
	}
	fmt.Printf("%#v \n", s) // == []string{"foo", "bar", "buz"}

	// JSON からマップ
	data = []byte(`{"key1":"val1","key2":"val2","key3":"val3"}`)
	m := map[string]string{}
	if err := json.Unmarshal(data, &m); err != nil {
		panic(err)
	}
	fmt.Printf("%#v \n", m) // == map[string]string{"key1":"val1", "key2":"val2", "key3":"val3"}
}

play_circleRun open_in_newRun In The Playground

参考ドキュメント: encoding/json

JSON エンコードまたはデコードする際にフィールド名を指定する #

構造体のフィールド定義のタグで JSON にエンコードした際あるいはデコードする際のフィールド名を指定できる。

package main

import (
	"encoding/json"
	"fmt"
)

type User struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

func main() {
	// JSON エンコード
	u1 := User{Name: "user1", Age: 10}
	data1, err := json.Marshal(u1)
	if err != nil {
		panic(err)
	}
	fmt.Println(string(data1)) // == {"name":"user1","age":10}

	// JSON デコード
	data2 := []byte(`{"name":"user2","age":20}`)
	u2 := new(User)
	if err := json.Unmarshal(data2, u2); err != nil {
		panic(err)
	}
	fmt.Printf("%#v \n", u2) // == &main.User{Name:"user2", Age:20}
}

play_circleRun open_in_newRun In The Playground

参考ドキュメント: encoding/json

JSON エンコード処理をカスタマイズする #

JSON のエンコードをする json.Marshal はエンコード対象が func MarshalJSON() ([]byte, error) を実装している場合に デフォルトのエンコード処理の代わりに MarshalJSON を実行する。

MarshalJSON はメソッドのレシーバからエンコード対象の情報を取得し、JSON に加工して []byte として返すメソッド。

package main

import (
	"encoding/json"
	"fmt"
)

type User struct {
	Name   string
	Age    int
	Gender int
}

func (u User) MarshalJSON() ([]byte, error) {
	m := map[string]interface{}{}

	m["name"] = u.Name
	m["years"] = u.Age

	switch u.Gender {
	case 1:
		m["gender"] = "male"
	case 2:
		m["gender"] = "female"
	default:
		m["gender"] = "other"
	}

	if u.Age < 20 {
		m["is_child"] = true
	}

	return json.Marshal(m)
}

func main() {
	u := User{Name: "user1", Age: 10, Gender: 2}
	data, err := json.Marshal(u)
	if err != nil {
		panic(err)
	}
	fmt.Println(string(data)) // == {"gender":"female","is_child":true,"name":"user1","years":10}
}

play_circleRun open_in_newRun In The Playground

参考ドキュメント: encoding/json

JSON デコード処理をカスタマイズする #

JSON のデコードをする json.Unmarshal はデコード先が func UnmarshalJSON(b []byte) error を実装している場合に デフォルトのデコード処理の代わりに UnmarshalJSON を実行する。

UnmarshalJSON は引数 b として JSON を受け取り、レシーバの値にデコードしたデータを入れていくメソッド。

package main

import (
	"encoding/json"
	"fmt"
)

type User struct {
	Name   string
	Age    int
	Gender int
}

func (u *User) UnmarshalJSON(b []byte) error {
	m := map[string]interface{}{}

	if err := json.Unmarshal(b, &m); err != nil {
		return err
	}

	if v, ok := m["name"]; ok {
		if s, ok := v.(string); ok {
			u.Name = s
		}
	}

	if v, ok := m["years"]; ok {
		if i, ok := v.(float64); ok {
			u.Age = int(i)
		}
	}

	if v, ok := m["gender"]; ok {
		if s, ok := v.(string); ok {
			switch s {
			case "male":
				u.Gender = 1
			case "female":
				u.Gender = 2
			default:
				u.Gender = 0
			}
		}
	}

	return nil
}

func main() {
	data := []byte(`{"gender":"female","is_child":true,"name":"user1","years":10}`)
	u := new(User)
	err := json.Unmarshal(data, u)
	if err != nil {
		panic(err)
	}
	fmt.Printf("%#v", u) // == &main.User{Name:"user1", Age:10, Gender:2}
}

play_circleRun open_in_newRun In The Playground

参考ドキュメント: encoding/json