determined

module
v1.0.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 23, 2023 License: MIT

README

determined

Determined unmarshals JSON string to go struct containing interfaces determined at run-time.

GoDoc

If object contains interface fields, unmarshaling by encoding/json will result in the error:

json: cannot unmarshal object into Go struct field XYZ of type ABC

The solution is to build customized Unmarshaler for the object. This package helps to implement Unmarshaler easily.

We may also use functions JJUnmarshal or JsonUnmarshal directly.

1. Installation

To download,

go get github.com/genelet/determined

2. Usage

In the following example, Child contains multiple-level objects including an interface in Geo. To unmarshal a JSON to Child by json.Unmarshal does not work.

We need to build UnmarshalJSON for Child.

package main

import (
	"encoding/json"
	"fmt"
	"github.com/genelet/determined"
)

type I interface {
    Area() float32
}

type Square struct {
    SX int `json:"sx"`
    SY int `json:"sy"`
}
func (self *Square) Area() float32 {
    return float32(self.SX * self.SY)
}

type Circle struct {
    Radius float32 `json:"radius"`
}
func (self *Circle) Area() float32 {
    return 3.14159 * self.Radius
}

type Geo struct {
    Name  string `json:"name"`
    Shape I      `json:"shape"`
}

type Toy struct {
    Geo     `json:"geo"`
    ToyName string  `json:"toy_name"`
    Price   float32 `json:"price"`
}

type Child struct {
    Toys []*Toy `json:"toys"`
    Family bool `json:"family"`
    Lastname string `json:"lastname"`
    endpoint []byte
    ref map[string]interface{}
}
func (self *Child) Assign(endpoint []byte, ref map[string]interface{}) {
    self.endpoint = endpoint
    self.ref = ref
}
func (self *Child) UnmarshalJSON(dat []byte) error {
    return xxx.JJUnmarshal(dat, self, self.endpoint, self.ref)
}

func main() {
    data1 := `{
"family":true,
"lastname":"Bizhang",
"toys":[{
    "toy_name":"roblox",
    "price":99.9,
    "geo":{
        "name": "peter shape",
        "shape": {
            "radius":1.234
        }
    }
},{
    "toy_name":"minecraft",
    "price":199.9,
    "geo":{
        "name": "marcus shape",
        "shape": {
            "sx":134,
            "sy":567
        }
    }
}]
}`

// build this Determined:
    data0 = `{"meta_type": 1, "single_name": "Child", "single_field": {
"Toys": {"meta_type": 4, "slice_name": ["Toy", "Toy"], "slice_field": [{
    "Geo": {"meta_type": 1, "single_name": "Geo", "single_field": {
        "Shape": {"meta_type": 1, "single_name": "Circle"}}}
    },{
    "Geo": {"meta_type": 1, "single_name": "Geo", "single_field": {
        "Shape": {"meta_type": 1, "single_name": "Square"}}}
    }]
}}}`
    ref := map[string]interface{}{"Geo": &Geo{}, "Circle": &Circle{}, "Square": &Square{}, "Toy": &Toy{}}
    child := new(Child)
    child.Assign([]byte(data0), ref)
    
    err := json.Unmarshal([]byte(data1), child)
    if err != nil { panic(err) }

    fmt.Printf("Toy 0: %#v\n", child.Toys[0])
    fmt.Printf("Toy 1: %#v\n", child.Toys[1])
}

The output will look like:

Toy 0: &main.Toy{Geo:main.Geo{Name:"peter shape", Shape:(*main.Circle)(0xc0000169f0)}, ToyName:"roblox", Price:99.9}
Toy 1: &main.Toy{Geo:main.Geo{Name:"marcus shape", Shape:(*main.Square)(0xc000016b20)}, ToyName:"minecraft", Price:199.9}

You may also build child's Determined manually by:

    sd1   := &Determined{MetaType: METASingle, SingleName: "Circle"}
    smap1 := DeterminedMap(map[string]*Determined{"Shape": sd1})
    gd1   := &Determined{MetaType: METASingle, SingleName: "Geo", SingleField: smap1}
    gmap1 := DeterminedMap(map[string]*Determined{"Geo": gd1})

    sd2   := &Determined{MetaType: METASingle, SingleName: "Square"}
    smap2 := DeterminedMap(map[string]*Determined{"Shape": sd2})
    gd2   := &Determined{MetaType: METASingle, SingleName: "Geo", SingleField: smap2}
    gmap2 := DeterminedMap(map[string]*Determined{"Geo": gd2})

    td1   := &Determined{MetaType: METASlice, SliceName: []string{"Toy", "Toy"}, SliceField: []DeterminedMap{gmap1, gmap2}}
    theMap := DeterminedMap(map[string]*Determined{"Toys": td1})

    theDetermined := &Determined{MetaType: METASingle, SingleName: "Child", SingleField: theMap}

Check the document

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL
JackTT - Gopher 🇻🇳