du512926 2016-08-03 17:21
浏览 60
已采纳

json的Golang结构,允许值可选地为数组

I am trying to change the policy for an s3 bucket on aws. I have created the following json structure for a policy:

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"`
}

Which works fine for putting bucket policies in place. The issue comes when I try to get the current policy and modify it.

If there is a statement that only has one AWS, Action, or Resource value, Amazon will convert it from an array to a simple value, causing my unmarshalling to fail.

Is there any way that I can specify AWS/Action/Resource values to be either a string slice or just a string?


I know that there are packages available that I could use to get around this to some extent (github.com/Jeffail/gabs, for example), but it would be cleaner to just create the JSON structure since it is fairly simple.

  • 写回答

2条回答 默认 最新

  • dongxing4643 2016-08-04 02:56
    关注

    As an alternative to interface{}, you can create a type called MaybeSlice and implement custom MarshalJSON and UnmarshalJSON methods on it.

    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
    }
    

    By implementing these methods the MaybeSlice type will satisfy the interfaces expected by json.Marshal and json.Unmarshal so you won't need to implement custom marshallers for all your types, just this one.

    MaybeSlice is a terrible name but hopefully you get the idea.

    These custom methods are easier with struct types, but I think the above is correct. If I remember correctly you need to make Action a *MaybeSlice to use the above.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 保护模式-系统加载-段寄存器
  • ¥15 电脑桌面设定一个区域禁止鼠标操作
  • ¥15 求NPF226060磁芯的详细资料