一、对象序列化概述
myJsonMarshal
二、系统环境&项目介绍

1.系统环境

操作系统:CentOS7
硬件信息:使用virtual box配置虚拟机(内存3G、磁盘30G)
编程语言:GO 1.15.2

2.项目的任务要求

func JsonMarshal(v interface{}) ([]byte, error)mytag:"你自己的定义"



三、具体程序设计及Golang代码实现

1.程序设计

reflectmyJsonMarshalmyJsonMarshal

2.JsonMarshal函数

//JsonMarshal 输入结构化数据,返回json字符流和error
func JsonMarshal(v interface{}) ([]byte, error) {
	b, err := Marshal(v)
	if err != nil {
		return nil, err
	}
	return b, nil
}

JsonMarshal函数是本程序包的主要接口,通过输入结构化数据,可以返回json字符流和报错信息error。


3.Marshal函数

//Marshal 将接口数据类型的数据转为json字符流
func Marshal(v interface{}) ([]byte, error) {
	json := reflect.ValueOf(v)
	typeJson := json.Type()

	switch typeJson.Kind() {
	case reflect.Invalid:
		return []byte("Invalid"), errors.New("Invalid")

	case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32,
		reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,
		reflect.Uint64, reflect.Float32, reflect.Float64:
		return []byte(fmt.Sprintf("%v", json.Interface())), nil

	case reflect.String:
		return StringTrans(v)

	case reflect.Struct:
		return StructTrans(v)

	case reflect.Map:
		return MapTrans(v)

	case reflect.Slice:
		return SliceTrans(v)

	case reflect.Array:
		return ArrayTrans(v)

	case reflect.Ptr:
		return PtrTrans(v)

	default:
		return []byte("unsupportedTypeTrans"), errors.New("unsupportedTypeTrans")
	}
}
reflect



4.StringTrans函数

//StringTrans 将string数据转为json字符流
func StringTrans(v interface{}) ([]byte, error) {
	json := reflect.ValueOf(v)
	return []byte("\"" + json.String() + "\""), nil
}

StringTrans函数将string数据转为json字符流


5.StructTrans函数

//StructTrans 将struct数据转为json字符流
func StructTrans(v interface{}) ([]byte, error) {
	json := reflect.ValueOf(v)
	typeJson := json.Type()
	b := "{"

	for i := 0; i < json.NumField(); i++ {

		if i > 0 {
			b = b + ","
		}

		tag := typeJson.Field(i).Tag.Get("mytag")
		if tag == "" {
			b = b + "\"" + typeJson.Field(i).Name + "\":"
		} else {
			b = b + "\"" + tag + "\":"
		}

		tmp, err := Marshal(json.Field(i).Interface())
		if err != nil {
			return nil, err
		}
		b = b + string(tmp)
	}

	b = b + "}"

	return []byte(b), nil
}
mytag:"你自己的定义"mytag:"name"

6.MapTrans函数

//MapTrans 将map数据转为json字符流
func MapTrans(v interface{}) ([]byte, error) {
	json := reflect.ValueOf(v)
	i := json.MapRange()
	first := true
	b := "{"

	for i.Next() {
		if first {
			first = false
		} else {
			b = b + ","
		}

		b = b + "\"" + fmt.Sprintf("\"%v\":", i.Key()) + "\":"

		tmp, err := Marshal(i.Value().Interface())
		if err != nil {
			return nil, err
		}
		b = b + string(tmp)
	}

	b = b + "}"

	return []byte(b), nil
}

MapTrans函数将map数据转为json字符流


7.SliceTrans函数

//SliceTrans 将slice数据转为json字符流
func SliceTrans(v interface{}) ([]byte, error) {
	json := reflect.ValueOf(v)
	b := "["

	for i := 0; i < json.Len(); i++ {
		if i > 0 {
			b = b + ","
		}

		tmp, err := Marshal(json.Index(i).Interface())
		if err != nil {
			return nil, err
		}

		b = b + string(tmp)
	}

	b = b + "]"
	return []byte(b), nil
}

SliceTrans函数将slice数据转为json字符流



8.ArrayTrans函数

//ArrayTrans 将array数据转为json字符流
func ArrayTrans(v interface{}) ([]byte, error) {
	json := reflect.ValueOf(v)
	b := "["

	for i := 0; i < json.Len(); i++ {
		if i > 0 {
			b = b + ","
		}

		tmp, err := Marshal(json.Index(i).Interface())
		if err != nil {
			return nil, err
		}

		b = b + string(tmp)
	}

	b = b + "]"
	return []byte(b), nil
}

ArrayTrans函数将array数据转为json字符流


9.PtrTrans函数

//PtrTrans 将ptr数据转为json字符流
func PtrTrans(v interface{}) ([]byte, error) {
	json := reflect.ValueOf(v)
	return Marshal(json.Elem().Interface())
}

StringTrans函数将ptr数据转为json字符流,指针变量编码时自动转换为它所指向的值。



四、程序测试

1.封装并使用程序包

将项目myJsonMarshal的myJsonMarshal.go文件的main函数注释掉,package改为package myJsonMarshal,然后执行如下指令:

go build

在其他路径下建立main.go,并调用myJsonMarshal.JsonMarshal函数即可。



2.功能测试

功能测试主要从用户角度测试程序包的功能,步骤如下:
创建main.go文件,内容如下(结构化数据类型及其数值可自定义):

package main

import (
	"fmt"

	"github.com/user/myJsonMarshal"
)

type Stu struct {
	Name  string `mytag:"name"`
	Age   int
	HIgh  bool
	Class *Class `mytag:"class"`
}

type Class struct {
	Name  string
	Grade int
}

func main() {
	//实例化一个数据结构,用于生成json字符串
	stu := Stu{
		Name: "张三",
		Age:  18,
		HIgh: true,
	}

	//指针变量
	cla := new(Class)
	cla.Name = "1班"
	cla.Grade = 3
	stu.Class = cla

	//Marshal失败时err!=nil
	jsonStu, err := myJsonMarshal.JsonMarshal(stu)
	if err != nil {
		fmt.Println("生成json字符串错误")
	}

	//jsonStu是[]byte类型,转化成string类型便于查看
	fmt.Println(string(jsonStu))
}

mytag:"你自己的定义"



3.单元测试

单元测试主要从程序员角度,对程序包的具体函数进行测试。
建立myJsonMarshal_test.go文件,对程序包的每个函数进行单元测试如下,代码如下:

package myJsonMarshal

import (
	"fmt"
	"testing"
)

type Stu struct {
	Name  string `mytag:"name"`
	Age   int
	HIgh  bool
	Class *Class `mytag:"class"`
}

type Class struct {
	Name  string
	Grade int
}

func Test_JsonMarshal(t *testing.T) {
	//实例化一个数据结构,用于生成json字符串
	stu := Stu{
		Name: "张三",
		Age:  18,
		HIgh: true,
	}

	//指针变量
	cla := new(Class)
	cla.Name = "1班"
	cla.Grade = 3
	stu.Class = cla

	//Marshal失败时err!=nil
	jsonStu, err := JsonMarshal(stu)
	if err != nil {
		fmt.Println("生成json字符串错误")
	}

	want := "{\"name\":\"张三\",\"Age\":18,\"HIgh\":true,\"class\":{\"Name\":\"1班\",\"Grade\":3}}"
	got := string(jsonStu)

	if got != want {
		t.Errorf("\n got %s\n want %s\n", got, want)
	}
}

func Test_Marshal(t *testing.T) {
	//实例化一个数据结构,用于生成json字符串
	stu := Stu{
		Name: "张三",
		Age:  18,
		HIgh: true,
	}

	//指针变量
	cla := new(Class)
	cla.Name = "1班"
	cla.Grade = 3
	stu.Class = cla

	//Marshal失败时err!=nil
	jsonStu, err := Marshal(stu)
	if err != nil {
		fmt.Println("生成json字符串错误")
	}

	want := "{\"name\":\"张三\",\"Age\":18,\"HIgh\":true,\"class\":{\"Name\":\"1班\",\"Grade\":3}}"
	got := string(jsonStu)

	if got != want {
		t.Errorf("\n got %s\n want %s\n", got, want)
	}
}

func Test_StringTrans(t *testing.T) {
	//实例化一个数据结构,用于生成json字符串
	test := "unit test"

	//Marshal失败时err!=nil
	jsonStu, err := StringTrans(test)
	if err != nil {
		fmt.Println("生成json字符串错误")
	}

	want := "\"unit test\""
	got := string(jsonStu)

	if got != want {
		t.Errorf("\n got %s\n want %s\n", got, want)
	}
}

func Test_StructTrans(t *testing.T) {
	//实例化一个数据结构,用于生成json字符串
	test := Class{
		Name:  "1班",
		Grade: 3,
	}

	//Marshal失败时err!=nil
	jsonStu, err := StructTrans(test)
	if err != nil {
		fmt.Println("生成json字符串错误")
	}

	want := "{\"Name\":\"1班\",\"Grade\":3}"
	got := string(jsonStu)

	if got != want {
		t.Errorf("\n got %s\n want %s\n", got, want)
	}
}

func Test_MapTrans(t *testing.T) {
	//实例化一个数据结构,用于生成json字符串
	test := map[string]int{
		"one":   1,
		"two":   2,
		"three": 3,
	}

	//Marshal失败时err!=nil
	jsonStu, err := MapTrans(test)
	if err != nil {
		fmt.Println("生成json字符串错误")
	}

	want := "{\"\"one\":\":1,\"\"two\":\":2,\"\"three\":\":3}"
	got := string(jsonStu)

	if got != want {
		t.Errorf("\n got %s\n want %s\n", got, want)
	}
}

func Test_SliceTrans(t *testing.T) {
	//实例化一个数据结构,用于生成json字符串
	test := []int{1, 2, 3}

	//Marshal失败时err!=nil
	jsonStu, err := SliceTrans(test)
	if err != nil {
		fmt.Println("生成json字符串错误")
	}

	want := "[1,2,3]"
	got := string(jsonStu)

	if got != want {
		t.Errorf("\n got %s\n want %s\n", got, want)
	}
}

func Test_ArrayTrans(t *testing.T) {
	//实例化一个数据结构,用于生成json字符串
	test := [3]int{1, 2, 3}

	//Marshal失败时err!=nil
	jsonStu, err := ArrayTrans(test)
	if err != nil {
		fmt.Println("生成json字符串错误")
	}

	want := "[1,2,3]"
	got := string(jsonStu)

	if got != want {
		t.Errorf("\n got %s\n want %s\n", got, want)
	}
}

func Test_PtrTrans(t *testing.T) {
	//实例化一个数据结构,用于生成json字符串
	test := new(Class)
	test.Name = "1班"
	test.Grade = 3

	//Marshal失败时err!=nil
	jsonStu, err := PtrTrans(test)
	if err != nil {
		fmt.Println("生成json字符串错误")
	}

	want := "{\"Name\":\"1班\",\"Grade\":3}"
	got := string(jsonStu)

	if got != want {
		t.Errorf("\n got %s\n want %s\n", got, want)
	}
}

在执行单元测试时,我们可以像上一次博客一样【博客】,在vscode中便捷地对每个函数进行test run,当编写单个函数的测试函数时,笔者更推荐这种方式。
当然,也可以像本次博客一样,在项目目录下,输入以下指令:

go test -v myJsonMarshal_test.go myJsonMarshal.go 

单元测试结果如下:

[henryhzy@localhost myJsonMarshal]$ go test -v myJsonMarshal_test.go myJsonMarshal.go 
=== RUN   Test_JsonMarshal
--- PASS: Test_JsonMarshal (0.00s)
=== RUN   Test_Marshal
--- PASS: Test_Marshal (0.00s)
=== RUN   Test_StringTrans
--- PASS: Test_StringTrans (0.00s)
=== RUN   Test_StructTrans
--- PASS: Test_StructTrans (0.00s)
=== RUN   Test_MapTrans
--- PASS: Test_MapTrans (0.00s)
=== RUN   Test_SliceTrans
--- PASS: Test_SliceTrans (0.00s)
=== RUN   Test_ArrayTrans
--- PASS: Test_ArrayTrans (0.00s)
=== RUN   Test_PtrTrans
--- PASS: Test_PtrTrans (0.00s)
PASS
ok  	command-line-arguments	0.002s



五、中文 api 文档

首先安装godoc如下:

git clone https://github.com/golang/tools $GOPATH/src/golang.org/x/tools
go build golang.org/x/tools

在项目myJsonMarshal所在目录下,执行如下指令:

go install
go doc
godoc -url="pkg/github.com/user/myJsonMarshal" > API.html

便会在当前目录下生成API.html文件:

【注意:程序包的函数名开头应为大写字母,对于函数A若含有注释,注释的开头也应为//A。】



六、完整代码

具体代码可见gitee仓库:gitee


七、References