2015-10-20 24 views
2

我們要在生產領域的JSON命名valuev。直到我們所有的用戶使用新的結構體,我們將繼續將舊的JSON結構體放入我們的代碼中。所以我們也想要處理這個。更名爲JSON場

如果你注意到,First是原來的結構,Second是新的結構。爲了處理這兩種結構,我創建了一個MyStruct和基於version,我複製到OldValueValue

​​

有沒有更好的方式來處理這個問題,而不是我的代碼。

Go Playground Link

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

Marshaler接口(https://golang.org/pkg/encoding/json/#Marshaler)用於你的結構,你可以按你認爲合適的方式編組''v'或'value'。 – elithrar

+3

如果你使用的是REST,你應該在你的REST URL中編碼版本,而不是在你周圍的數據中編碼。也就是說,所有包含'/ v1 /'作爲其路徑部分組件的API URL都必須返回並使用根據「v1」規則格式化的JSON。如果您需要更改數據格式,請介紹「v2」,提供實施新規則的新API端點並逐步過渡您的客戶端。轉換之後,「v1」端點變得過時並且可以安全地移除。 – kostix

+0

謝謝。在這裏,我們沒有使用REST API。在這種情況下,我們使用JavaScript腳本自動收集來自不同客戶端的數據。從技術上講,我們也可以在這裏引入REST方法,但我們現在沒有這樣做。我們將在未來考慮它。謝謝你的提示。 – Sundar

回答

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 
} 

遊樂場: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 
} 

首先,解組到內部結構,檢查版本,如果它是一個古老的一個,得到舊的價值。

遊樂場:https://play.golang.org/p/AaULW6vJz_

+0

謝謝@Ainar-G。我把你的方法插入到相同的結構中,然後只是複製它,如果版本較低,則將它插入新變量中。 – Sundar

0

我會選擇,因爲他們都是同一個真的不在這裏使用3種不同的結構。

修改您的結構MyStruct,並將json:"value"加載到一個新變量中,並且如果值不存在,則Unmarshal的一部分應將值複製到Value變量中。

不過,我想第二Kostix的建議在這裏。加載和保存數據的API或進程應該嘗試根據建議的機制對版本進行說明。將av#添加到您的URI中,或者如果您要將項目保存到磁盤,則可以使用版本號保存它,然後處理每個結構對應於正確版本的內部部分:

{ 
    "version": 1, 
    "struct": { ... } 
} 
+0

謝謝。在這裏,我們沒有使用REST API。對於REST,我們使用不同的版本。但是,在這種情況下,我們正在使用js自動從不同的客戶端收集數據。從技術上講,我們也可以在這裏引入REST方法,但我們現在沒有這樣做。我們將在未來考慮它。謝謝你的提示。 – Sundar