Created
April 13, 2020 13:30
-
-
Save eagletmt/250e60015555d29badbbcff769a491ee to your computer and use it in GitHub Desktop.
How to deserialize internally tagged JSON in Go?
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"items": [ | |
{"type": "A", "foo": "bar"}, | |
{"type": "B", "hoge": "fuga"} | |
] | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"encoding/json" | |
"fmt" | |
"io/ioutil" | |
"log" | |
) | |
type Object struct { | |
Items []json.RawMessage `json:"items"` | |
} | |
type ItemA struct { | |
Type string `json:"type"` | |
Foo string `json:"foo"` | |
} | |
type ItemB struct { | |
Type string `json:"type"` | |
Hoge string `json:"hoge"` | |
} | |
func main() { | |
body, err := ioutil.ReadFile("input.json") | |
if err != nil { | |
log.Fatal(err) | |
} | |
var obj Object | |
err = json.Unmarshal(body, &obj) | |
if err != nil { | |
log.Fatal(err) | |
} | |
for _, item := range obj.Items { | |
var itemA ItemA | |
var itemB ItemB | |
if json.Unmarshal(item, &itemA) == nil && itemA.Type == "A" { | |
fmt.Printf("ItemA %s\n", itemA.Foo) | |
} else if json.Unmarshal(item, &itemB) == nil && itemA.Type == "B" { | |
fmt.Printf("ItemB %s\n", itemB.Hoge) | |
} else { | |
panic("Unknown item") | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#[derive(Debug, serde::Deserialize)] | |
struct Object { | |
items: Vec<Item>, | |
} | |
#[derive(Debug, serde::Deserialize)] | |
#[serde(tag = "type")] | |
enum Item { | |
A(ItemA), | |
B(ItemB), | |
} | |
#[derive(Debug, serde::Deserialize)] | |
struct ItemA { | |
foo: String, | |
} | |
#[derive(Debug, serde::Deserialize)] | |
struct ItemB { | |
hoge: String, | |
} | |
fn main() -> Result<(), Box<dyn std::error::Error>> { | |
let file = std::fs::File::open("input.json")?; | |
let obj: Object = serde_json::from_reader(file)?; | |
for item in obj.items { | |
match item { | |
Item::A(item_a) => println!("ItemA {}", item_a.foo), | |
Item::B(item_b) => println!("ItemB {}", item_b.hoge), | |
} | |
} | |
Ok(()) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I found a Go-ish way using
UnmarshalJSON
: https://gist.github.com/nekketsuuu/21cc9b47ef0dbff168a7ccfe4607f6b7Doc: https://pkg.go.dev/encoding/json?tab=doc#Unmarshaler