## Sometimes we have to deal with JSON that with unknown data types.
```
[
{
"kind":"dog",
"attr":{
"type":"Collie",
"color":"black"
}
},
{
"kind":"duck",
"attr":{
"weight":1.2
}
}
]
```
```Go
type DogAttr struct {
Type string `json:"type"`
Color string `json:"color"`
}
type DuckAttr struct {
Weight float64
}
```
```Go
func TestDecodeRaw(t *testing.T) {
var factory = NewFactory()
factory.MustReg("dog", (*DogAttr)(nil))
factory.MustReg("duck", (*DuckAttr)(nil))
type AnimalRaw struct {
Kind string `json:"kind"`
Attr json.RawMessage `json:"attr"`
}
var animals []AnimalRaw
json.Unmarshal(sampleJson, &animals)
for i, v := range animals {
d, _ := factory.Create(v.Kind)
json.Unmarshal(v.Attr, d)
fmt.Printf("index %d, kind=%s attr=%#v\n", i, v.Kind, d)
}
// Output:
// index 0, kind=dog attr=&lab27.DogAttr{Type:"Collie", Color:"black"}
// index 1, kind=duck attr=&lab27.DuckAttr{Weight:1.2}
}
```
```Go
func TestEncodeRaw(t *testing.T) {
type AnimalRaw struct {
Kind string `json:"kind"`
Attr json.RawMessage `json:"attr"`
}
var animals = []AnimalRaw{
AnimalRaw{
Kind: "dog",
Attr: []byte(`{"type": "Collie","color": "white"}`), // ugly
},
AnimalRaw{
Kind: "duck",
Attr: []byte(`{"Weight": 2.34}`), // ugly
},
}
b, _ := json.MarshalIndent(animals, "", " ")
fmt.Println(string(b))
// Output:
// [
// {
// "kind": "dog",
// "attr": {
// "type": "Collie",
// "color": "white"
// }
// },
// {
// "kind": "duck",
// "attr": {
// "Weight": 2.34
// }
// }
// ]
}
```
from field "Raw" into field "D" and can direct encoding JSON from field "D".
```Go
// FlexObject is an object that can encoding/decoding JSON between flex Go types.
// It implements Marshaler and Unmarshaler and can delay JSON decoding
// from field Raw and can direct encoding from field D.
type FlexObject struct {
Raw []byte // raw bytes for delay JSON decoding
D interface{} // flex object for JSON encoding
}
// MarshalJSON encoding field D as JSON.
func (f FlexObject) MarshalJSON() ([]byte, error) {
return Marshal(f.D)
}
// UnmarshalJSON copy data into field Raw.
func (f *FlexObject) UnmarshalJSON(data []byte) error {
f.Raw = append(f.Raw[0:0], data...)
return nil
}
```
```Go
func TestFlexObjectFactory(t *testing.T) {
var factory = NewFactory()
factory.MustReg("dog", (*DogAttr)(nil))
factory.MustReg("duck", (*DuckAttr)(nil))
type Animal struct {
Kind string `json:"kind"`
Attr json.FlexObject `json:"attr"`
}
var animals []Animal
json.Unmarshal(sampleJson, &animals)
for i, v := range animals {
factory.UnmarshalJSONForFlexObj(v.Kind, &v.Attr)
fmt.Printf("index %d, kind=%s attr=%#v\n", i, v.Kind, v.Attr.D)
}
// Output:
// index 0, kind=dog attr=&lab27.DogAttr{Type:"Collie", Color:"black"}
// index 1, kind=duck attr=&lab27.DuckAttr{Weight:1.2}
}
```
```Go
func TestGenerateJsonByFlexObject(t *testing.T) {
type Animal struct {
Kind string `json:"kind"`
Attr json.FlexObject `json:"attr"`
}
var animals = []Animal{
Animal{
Kind: "dog",
Attr: json.FlexObject{
D: DogAttr{
Type: "Collie",
Color: "white",
},
},
},
Animal{
Kind: "duck",
Attr: json.FlexObject{
D: DuckAttr{
Weight: 2.34,
},
},
},
}
b, _ := json.MarshalIndent(animals, "", " ")
fmt.Println(string(b))
// Ooutput:
// [
// {
// "kind": "dog",
// "attr": {
// "type": "Collie",
// "color": "white"
// }
// },
// {
// "kind": "duck",
// "attr": {
// "Weight": 2.34
// }
// }
// ]
}
```
**If the proposal is accepted, it will be my pleasure to push the PR.**