wechatpay-apiv3 / wechatpay-go

微信支付 APIv3 的官方 Go Library
https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pages/index.shtml
Apache License 2.0
982 stars 140 forks source link

结构体 MarshalJSON 实现做了大量职责之外的事 #173

Open lostpg opened 1 year ago

lostpg commented 1 year ago

这个结构体的MarshalJSON方法 所示,库中所有的请求和返回结构体的MarshalJSON方法实现都硬编码了序列化后的 key,这种做法绕过了结构体注解中对json key名的标注。

重新梳理了一下,MarshalJSON实现的问题不在于用了map和硬编码结构体json key,而是MarshalJSON广泛用于了「检查必填参数是否填入」这个函数名职责以外的事情,导致了大量MarshalJSON的重复编码,同时无视了结构体注解。

检查必填参数这个事情感觉可以和参数加解密一样,用一个注解+单独的检查方法完成。

lostpg commented 1 year ago

补充,对嵌套结构体测试也是相同结果

package test

import (
    "bytes"
    "encoding/json"
    "testing"

    "github.com/wechatpay-apiv3/wechatpay-go/core"
    "github.com/wechatpay-apiv3/wechatpay-go/services/partnerpayments/h5"
)

func Test(t *testing.T) {
    r := h5.Detail{
        CostPrice: core.Int64(300),
        InvoiceId: core.String("INvOIceId"),
        GoodsDetail: []h5.GoodsDetail{
            {
                MerchantGoodsId:  core.String("MeRcHAntgOODsid1"),
                WechatpayGoodsId: core.String("WeChATPayGOoDsid1"),
                GoodsName:        core.String("GOoDSnaMe1"),
                Quantity:         core.Int64(11),
                UnitPrice:        core.Int64(100),
            },
            {
                MerchantGoodsId:  core.String("meRcHaNTGOoDSID2"),
                WechatpayGoodsId: core.String("WEchaTPAYgOOdSiD2"),
                GoodsName:        core.String("GOoDsNAmE2"),
                Quantity:         core.Int64(22),
                UnitPrice:        core.Int64(200),
            },
        },
    }
    b, err := r.MarshalJSON()
    if err != nil {
        t.Fatal("MarshalJSON: ", err)
    }
    b2, err := json.Marshal(r)
    if err != nil {
        t.Fatal("json.Marshal: ", err)
    }
    if !bytes.Equal(b, b2) {
        t.Errorf("unequal marshal\nMarshalJSON : %s\njson.Marshal: %s", b, b2)
    }
}
xy-peng commented 1 year ago

感谢 @lostpg ,是个很好的建议。当初设计时,我们对这一点有过讨论。因为这部分代码是自动生成的,所以我们没有纠结重复编码。

但是目前的设计确实违背了单一职责的原则。我们再讨论下。