我正在尝试更改aws上s3存储桶的策略。我为策略创建了以下json结构:
type Policy struct {
Version string `json:"Version"`
Id string `json:"Id"`
Statement []Statement `json:"Statement"`
}
type Statement struct {
Sid string `json:"Sid"`
Effect string `json:"Effect"`
Principal Principal `json:"Principal"`
Action []string `json:"Action"`
Resource []string `json:"Resource"`
}
type Principal struct {
AWS[]string `json:"AWS"`
}
适用于放置存储桶策略的方法。当我尝试获取当前策略并对其进行修改时,问题就出现了。
如果某个语句只有一个AWS,Action或Resource值,则Amazon会将其从一个数组转换为一个简单的值,从而导致我的解组失败。
有什么方法可以将AWS / Action / Resource值指定为字符串切片或只是字符串?
我知道有一些可用的软件包我可以在某种程度上解决这个问题(例如github.com/Jeffail/gabs
),但是创建JSON结构会更简洁,因为它非常简单。 / p>
答案 0 :(得分:2)
作为interface{}
的替代方法,您可以创建一个名为MaybeSlice的类型,并在其上实现自定义MarshalJSON和UnmarshalJSON方法。
type MaybeSlice []string
func (ms *MaybeSlice) MarshalJSON() ([]byte, error) {
// Use normal json.Marshal for subtypes
if len(*ms) == 1 {
return json.Marshal(([]string)(*ms)[0])
}
return json.Marshal(*ms)
}
func (ms *MaybeSlice) UnmarshalJSON(data []byte) error {
// Use normal json.Unmarshal for subtypes
var s string
if err := json.Unmarshal(data, &s); err != nil {
var v []string
if err := json.Unmarshal(data, &v); err != nil {
return err
}
*ms = v
return nil
}
*ms = []string{s}
return nil
}
通过实现这些方法,MaybeSlice类型将满足json.Marshal和json.Unmarshal所期望的接口,因此您不需要为所有类型实现自定义编组器,只需要这个。
MaybeSlice是一个可怕的名字,但希望你能得到这个想法。
使用struct类型可以更轻松地使用这些自定义方法,但我认为上述方法是正确的。如果我没记错,您需要Action
*MaybeSlice
使用上述内容。
答案 1 :(得分:1)
如果您要解析的字段类型无法保证,请使用interface{}
:
type Statement struct {
Sid string `json:"Sid"`
Effect string `json:"Effect"`
Principal Principal `json:"Principal"`
Action interface{} `json:"Action"`
Resource interface{} `json:"Resource"`
}
使用类型开关访问基础原始数据类型:
//Example: Trying to access Action member of a statement myStatement.
switch a := myStatement.Action.(type) {
case []string:
//Action is a slice. Handle it accordingly.
case string:
//Action is a string. Handle it accordingly.
default:
//Some other datatype that can be returned by aws?
}
或者你可以为两种情况都有单独的结构,如果Unmarshaling一个失败,将它解组到另一个结构中,就像这样:
err := json.Unmarshal(jsonStr, &struct1)
if err != nil {
fmt.Println(err)
err = json.Unmarshal(jsonStr, &struct2)
}