Determined marshals and unmarshals JSON data to go struct containing interfaces determined at run-time.
Note: The HCL parsing feature has been extracted and moved to a separate Github package github.com/genelet/horizon. The old HCL code in this package is frozen for compatibility reasons.
go get github.com/genelet/determinedThe core Golang package encoding/json is an exceptional library for managing JSON data. However, to decode the interface type, it necessitates writing a customized Unmarshaler for the target object. While this isn’t typically a challenging task, it often results in repetitive code for different types of objects and packages.
Therefore, determined was created to streamline the coding process and enhance productivity.
To decode JSON to an object containing interface types, use det.JsonUnmarshal.
// JsonUnmarshal unmarshals JSON data with interfaces determined by spec.
//
// - dat: JSON data
// - current: object as pointer
// - spec: *schema.Struct
// - ref: struct map, with key being string name and value reference to struct
func JsonUnmarshal(dat []byte, current interface{}, spec *schema.Struct, ref map[string]interface{}) errorYou first need to define the structure of your interfaces using schema.NewStruct from the github.com/genelet/schema package.
Here is an example of how to use determined to decode JSON data where fields are interfaces.
package main
import (
"fmt"
"github.com/genelet/determined/det"
"github.com/genelet/schema"
)
type geo struct {
Name string `json:"name"`
Shape inter `json:"shape"`
}
type inter 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 toy struct {
Geo geo `json:"geo"`
ToyName string `json:"toy_name"`
Price float32 `json:"price"`
}
type child struct {
Brand map[string]*toy `json:"brand"`
Age int `json:"age"`
}
func main() {
data1 := `{
"age" : 5,
"brand" : {
"abc1" : {
"toy_name" : "roblox",
"price" : 99.9,
"geo" : {
"name" : "medium shape",
"shape" : { "radius" : 1.234 }
}
},
"def2" : {
"toy_name" : "minecraft",
"price" : 9.9,
"geo" : {
"name" : "square shape",
"shape" : { "sx" : 5, "sy" : 6 }
}
}
}
}`
// Define the structure of the interfaces for the specific data
spec, err := schema.NewStruct(
"child", map[string]interface{}{
"Brand": map[string][2]interface{}{
"abc1":[2]interface{}{"toy", map[string]interface{}{
"Geo": [2]interface{}{
"geo", map[string]interface{}{"Shape": "circle"}}}},
"def2":[2]interface{}{"toy", map[string]interface{}{
"Geo": [2]interface{}{
"geo", map[string]interface{}{"Shape": "square"}}}},
},
},
)
if err != nil {
panic(err)
}
// Map string names to actual struct pointers
ref := map[string]interface{}{
"toy": &toy{},
"geo": &geo{},
"circle": &circle{},
"square": &square{},
}
c := new(child)
err = det.JsonUnmarshal([]byte(data1), c, spec, ref)
if err != nil {
panic(err)
}
fmt.Printf("Age: %v\n", c.Age)
fmt.Printf("Brand abc1: %#v\n", c.Brand["abc1"])
fmt.Printf("Brand abc1 Shape: %#v\n", c.Brand["abc1"].Geo.Shape)
fmt.Printf("Brand def2: %#v\n", c.Brand["def2"])
fmt.Printf("Brand def2 Shape: %#v\n", c.Brand["def2"].Geo.Shape)
}For more details on how to construct the spec using NewStruct, please refer to DOCUMENT.md.