D
D
Dmitry Sviridov2021-06-20 12:33:59
go
Dmitry Sviridov, 2021-06-20 12:33:59

How to correctly decode JSON to UnmarshalJSON?

There are 2 structures into which I want to decode the JSON received via the API:

type TemplateCategory struct {
  ID              int    `json:"id"`
  Name            string `json:"name"`
}

type Template struct {
  Name            string                `json:"name"`
  CategoryInfo    *TemplateCategoryType `json:"category_info"`
}


In the absence of category_info in the template, this arrives: [] . Accordingly, I wrote my UnmarshalJSON:

type TemplateCategoryType struct {
  *TemplateCategory
}

func (t *TemplateCategoryType) UnmarshalJSON(b []byte) error {
  s := strings.Trim(string(b), "\"")
  if s == "[]" {
    t.TemplateCategory = nil
    return nil
  }

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

  t.TemplateCategory = &category
  return nil
}


But here the problem arises that in template.CategoryInfo I get not just a pointer to the structure, but this &{0xc000134d20} (pointer to the TemplateCategoryType structure, inside which is a pointer to TemplateCategory or nil) - that is, I have to access data for getting a category like this: template.CategoryInfo.CategoryInfo. How can I make my template.CategoryInfo either have a pointer to a structure or just nil instead of ? &{nil}

Answer the question

In order to leave comments, you need to log in

1 answer(s)
E
Evgeny Mamonov, 2021-06-20
@dimuska139

There is not a very beautiful option, but if you need to quickly solve the problem - you can use it.
If you have a small load - you can use it on an ongoing basis.
If the load is huge - then you need to do it differently.
Only wherever the character `_` must be done error handling.

package main

import (
    "encoding/json"
    "fmt"
    "log"
)

type TemplateCategory struct {
    ID   int    `json:"id"`
    Name string `json:"name"`
}

type Template struct {
    Name         string            `json:"name"`
    CategoryInfo *TemplateCategory `json:"category_info"`
}

func (t *Template) UnmarshalJSON(b []byte) error {
    var result map[string]interface{}
    if err := json.Unmarshal(b, &result); err != nil {
        return err
    }

    if t == nil {
        t = &Template{}
    }
    t.Name, _ = result[`name`].(string)

    categoryInfo, isMap := result[`category_info`].(map[string]interface{})
    if isMap {
        t.CategoryInfo = &TemplateCategory{}
        t.CategoryInfo.ID, _ = categoryInfo[`id`].(int)
        t.CategoryInfo.Name, _ = categoryInfo[`name`].(string)
    }

    return nil
}

func main() {
    json1 := []byte(`{
        "name": "Мой шаблон",
        "category_info": {
            "id": 109,
            "name": "Тест"
        }
    }`)

    json2 := []byte(`{
        "name": "Мой шаблон",
        "category_info": []
    }`)

    var data1 Template
    err := json.Unmarshal(json1, &data1)
    if err != nil {
        log.Fatalf(`json1: %s`, err)
    }

    var data2 Template
    err = json.Unmarshal(json2, &data2)
    if err != nil {
        log.Fatalf(`json2: %s`, err)
    }

    fmt.Printf("data1: %+v\n", data1)
    fmt.Printf("data1.CategoryInfo: %+v\n\n", data1.CategoryInfo)

    fmt.Printf("\n\ndata2: %+v\n", data2)
    fmt.Printf("data2.CategoryInfo: %+v\n\n", data2.CategoryInfo)
}

Output:
data1: {Name:My CategoryInfo template:0xc00000c0c0}
data1.CategoryInfo: &{ID:0 Name:Test}
data2: {Name:My CategoryInfo template:}
data2.CategoryInfo:

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question