具有io.Reader的Golang结构无法序列化

pra*_*yay 1 serialization go deserialization

我试图将struct下面的序列化为byte []以将其存储到DB中,然后在从DB中读取它时我将其反序列化.

type Response struct {
    Headers map[string][]string
    Body    io.Reader
    Status  int
}
Run Code Online (Sandbox Code Playgroud)

下面是我如何创建响应对象并为其设置值的代码.

resp := new(Response)
resp.Body = bytes.NewReader(outBytes) //outBytes is byte[]
resp.Headers.SetKeyValue("Content-Type", "text/json") //SetKeyValue is the method created for adding headers
resp.Headers.SetKeyValue("Url-Type", "broker")
resp.Status = 200
Run Code Online (Sandbox Code Playgroud)

我正在使用json.Marshal()来序列化resp对象,如下所示.

b, _ := json.Marshal(resp)
Run Code Online (Sandbox Code Playgroud)

下面是代码,我用来反序列化.

var r Response
r.Body = &bytes.Buffer{}
json.Unmarshal(b,&r)
Run Code Online (Sandbox Code Playgroud)

问题是反序列化,我无法获得resp.Body对象.尽管设置了体对象,但它总是为零或空白(见上文).我可以从反序列化而不是Body获取结构的Headers和status字段.

我知道有一些东西需要处理Body字段,它是一个io.Reader.

任何帮助都会非常棒.

Sar*_*lai 5

Read()简答: JSON marshaller不会使用函数从io.Reader读取字符串.而不是使用io.Reader您可以使用实现Marshaler接口的类型.

Marshaller的工作原理: Marshal以递归方式遍历值v.如果遇到的值实现了Marshaler接口并且不是nil指针,则Marshal会调用其MarshalJSON方法来生成JSON.如果没有MarshalJSON方法,但值实现了encoding.TextMarshaler,Marshal会调用它的MarshalText方法.nil指针异常不是绝对必要的,但在UnmarshalJSON的行为中模仿了类似的必要异常.

否则,Marshal使用以下type-dependent默认编码:

  • 布尔值编码为JSON布尔值.
  • 浮点,整数和数字值编码为JSON数字.

实现 这就是你可以做的

type Response struct {
    Headers map[string][]string
    Body    *JSONReader
    Status  int
}

type JSONReader struct {
    *bytes.Reader
}

func NewJSONReader(outBytes []byte) *JSONReader {
    jr := new(JSONReader)
    jr.Reader = bytes.NewReader(outBytes)
    return jr
}

func (js JSONReader) MarshalJSON() ([]byte, error) {
    data, err := ioutil.ReadAll(js.Reader)
    if err != nil {
        return nil, err
    }
    data = []byte(`"` + string(data) + `"`)
    return data, nil
}

// UnmarshalJSON sets *jr to a copy of data.
func (jr *JSONReader) UnmarshalJSON(data []byte) error {
    if jr == nil {
        return errors.New("json.JSONReader: UnmarshalJSON on nil pointer")
    }
    if data == nil {
        return nil
    }
    data = []byte(strings.Trim(string(data), "\""))
    jr.Reader = bytes.NewReader(data)
    return nil
}
Run Code Online (Sandbox Code Playgroud)

这是一个go操场链接,其中包含实现和示例用法:link