英文:
Renamed JSON field
问题
我们想要在生产环境中将一个JSON字段value
重命名为v
。在所有用户都使用新的结构之前,我们将继续接收旧的JSON结构到我们的代码中。因此,我们也希望处理这个问题。
如果你注意到,First
是原始结构,Second
是新的结构。为了处理这两个结构,我创建了一个MyStruct
,根据version
的值,将OldValue
复制到Value
中。
if m.Version <= 1 {
m.Value = m.OldValue
}
有没有更好的方法来处理这个问题,而不是使用我的代码。
package main
import "fmt"
import "encoding/json"
import "log"
type First struct {
Version int `json:"version"`
Value int `json:"value"`
}
type Second struct {
Version int `json:"version"`
Value int `json:"v"`
}
type MyStruct struct {
Version int `json:"version"`
OldValue int `json:"value"`
Value int `json:"v"`
}
func main() {
oldValue := []byte(`{"version":1, "value":5}`)
newValue := []byte(`{"version":2, "v":7}`)
var m MyStruct
err := json.Unmarshal(newValue, &m)
if err != nil {
log.Fatal(err)
}
fmt.Println("New Struct")
fmt.Println(m.Value)
err = json.Unmarshal(oldValue, &m)
if err != nil {
log.Fatal(err)
}
fmt.Println("Old Struct")
if m.Version <= 1 {
m.Value = m.OldValue
}
fmt.Println(m.Value)
}
英文:
We want to rename a JSON field value
to v
in production. Till all our users use the new struct, we would continue to get old JSON structs into our code. So we want to handle this as well.
If you notice, First
is the original structure, Second
is the new structure. To handle both these structures, I have created a MyStruct
and based on version
, I copy the OldValue
into Value
if m.Version <= 1 {
m.Value = m.OldValue
}
Is there a better way to handle this, instead of my code.
package main
import "fmt"
import "encoding/json"
import "log"
type First struct {
Version int `json:"version"`
Value int `json:"value"`
}
type Second struct {
Version int `json:"version"`
Value int `json:"v"`
}
type MyStruct struct {
Version int `json:"version"`
OldValue int `json:"value"`
Value int `json:"v"`
}
func main() {
oldValue := []byte(`{"version":1, "value":5}`)
newValue := []byte(`{"version":2, "v":7}`)
var m MyStruct
err := json.Unmarshal(newValue, &m)
if err != nil {
log.Fatal(err)
}
fmt.Println("New Struct")
fmt.Println(m.Value)
err = json.Unmarshal(oldValue, &m)
if err != nil {
log.Fatal(err)
}
fmt.Println("Old Struct")
if m.Version <= 1 {
m.Value = m.OldValue
}
fmt.Println(m.Value)
}
答案1
得分: 1
你可以使用一次解组来实现,尽管你需要另一个类型:
type Second struct {
Version int `json:"version"`
Value int `json:"v"`
}
type SecondWithOldValue struct {
OldValue int `json:"value"`
Second
}
type MyStruct SecondWithOldValue
func (v *MyStruct) UnmarshalJSON(b []byte) error {
if err := json.Unmarshal(b, (*SecondWithOldValue)(v)); err != nil {
return err
}
if v.Version <= 1 {
v.Value = v.OldValue
}
return nil
}
Playground: https://play.golang.org/p/yII-ncxnU4。
以下是旧的回答。
如果你可以接受双重解组,可以这样做:
type Second struct {
Version int `json:"version"`
Value int `json:"v"`
}
type MyStruct struct {
Second
}
func (v *MyStruct) UnmarshalJSON(b []byte) error {
if err := json.Unmarshal(b, &v.Second); err != nil {
return err
}
if v.Version <= 1 {
var oldV struct{ Value int }
if err := json.Unmarshal(b, &oldV); err != nil {
return err
}
v.Value = oldV.Value
}
return nil
}
首先,解组到内部结构体,检查版本,如果是旧版本,则获取旧值。
Playground: https://play.golang.org/p/AaULW6vJz_。
英文:
EDIT: You can actually do it with one unmarshaling, albeit you'll need another type:
type Second struct {
Version int `json:"version"`
Value int `json:"v"`
}
type SecondWithOldValue struct {
OldValue int `json:"value"`
Second
}
type MyStruct SecondWithOldValue
func (v *MyStruct) UnmarshalJSON(b []byte) error {
if err := json.Unmarshal(b, (*SecondWithOldValue)(v)); err != nil {
return err
}
if v.Version <= 1 {
v.Value = v.OldValue
}
return nil
}
Playground: https://play.golang.org/p/yII-ncxnU4.
Old answer below.
If you're OK with double unmarshaling, you can do it like this:
type Second struct {
Version int `json:"version"`
Value int `json:"v"`
}
type MyStruct struct {
Second
}
func (v *MyStruct) UnmarshalJSON(b []byte) error {
if err := json.Unmarshal(b, &v.Second); err != nil {
return err
}
if v.Version <= 1 {
var oldV struct{ Value int }
if err := json.Unmarshal(b, &oldV); err != nil {
return err
}
v.Value = oldV.Value
}
return nil
}
First, unmarshal into the inner struct, check version, and if it's an old one, get the old value.
Playground: https://play.golang.org/p/AaULW6vJz_.
答案2
得分: 0
我会选择不在这里使用三个不同的结构体,因为它们实际上都是相同的。
按照你修改的方式修改你的结构体MyStruct,并将json:"value"
加载到一个新变量中,同时在解组过程中,如果Value不存在,将值复制到Value变量中。
然而,我赞同Kostix的建议。你的API或加载和保存数据的过程应该尝试通过建议的机制来考虑版本控制。在URI中添加一个v#,或者如果你将项目保存到磁盘中,可以使用版本号保存,并根据正确版本对应的结构体处理内部部分:
{
"version": 1,
"struct": { ... }
}
英文:
I would opt to not use 3 different struct here as they are all the same really.
Modify your struct MyStruct as you have and load the json:"value"
into a new variable as you are and part of your Unmarshal should copy the value into the Value variable if Value is not present.
However I would second Kostix's recommendation here. Your API or process that loads and saves data should try to account for versioning by the mechanism suggested. Add a v# to your URI or if you're saving the item down to disk, then perhaps save it with a version number as such and then process the inner section per struct that corresponds to the proper version:
{
"version": 1,
"struct": { ... }
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论