From 1bc30f9eda197c34a2e2d6490f2b84da0f701b6c Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Fri, 4 Dec 2020 22:55:56 +0100 Subject: [PATCH] add support for *JSON methods --- codec/amino_codec.go | 35 ++++++++++++++++++++++++++++------- codec/amino_codec_test.go | 3 +++ codec/codec.go | 4 ++-- codec/codec_common_test.go | 10 ++++++---- codec/proto_codec.go | 15 +++++++-------- 5 files changed, 46 insertions(+), 21 deletions(-) diff --git a/codec/amino_codec.go b/codec/amino_codec.go index e8327295dbb8..c9dcd9007f79 100644 --- a/codec/amino_codec.go +++ b/codec/amino_codec.go @@ -81,9 +81,9 @@ func (ac *AminoCodec) MustUnmarshalJSON(bz []byte, ptr proto.Message) { ac.LegacyAmino.MustUnmarshalJSON(bz, ptr) } -// MarshalInterface implements BinaryMarshaler interface -// The `o` must be an interface and must must implement ProtoMarshaler (it will panic otherwise). -// NOTE: if you use a concrete type, you should use MarshalBinaryBare instead +// MarshalInterface is a convenience function for amino marshaling interfaces. +// The `i` must be an interface. +// NOTE: to marshal a concrete type, you should use MarshalBinaryBare instead func (ac *AminoCodec) MarshalInterface(i proto.Message) ([]byte, error) { if err := assertNotNil(i); err != nil { return nil, err @@ -91,13 +91,34 @@ func (ac *AminoCodec) MarshalInterface(i proto.Message) ([]byte, error) { return ac.LegacyAmino.MarshalBinaryBare(i) } -// UnmarshalInterface is a convenience function for proto unmarshaling interfaces. -// `ptr` must be a pointer to an interface. If you use a concrete type you should use -// UnmarshalBinaryBare +// UnmarshalInterface is a convenience function for amino unmarshaling interfaces. +// `ptr` must be a pointer to an interface. +// NOTE: to unmarshal a concrete type, you should use UnarshalBinaryBare instead // // Example: // var x MyInterface -// err := UnmarshalAny(bz, &x) +// err := UnmarshalInterface(bz, &x) func (ac *AminoCodec) UnmarshalInterface(bz []byte, ptr interface{}) error { return ac.LegacyAmino.UnmarshalBinaryBare(bz, ptr) } + +// MarshalInterfaceJSON is a convenience function for amino marshaling interfaces. +// The `i` must be an interface. +// NOTE: to marshal a concrete type, you should use MarshalJSON instead +func (ac *AminoCodec) MarshalInterfaceJSON(i proto.Message) ([]byte, error) { + if err := assertNotNil(i); err != nil { + return nil, err + } + return ac.LegacyAmino.MarshalJSON(i) +} + +// UnmarshalInterfaceJSON is a convenience function for amino unmarshaling interfaces. +// `ptr` must be a pointer to an interface. +// NOTE: to unmarshal a concrete type, you should use UnarshalJSON instead +// +// Example: +// var x MyInterface +// err := UnmarshalInterfaceJSON(bz, &x) +func (ac *AminoCodec) UnmarshalInterfaceJSON(bz []byte, ptr interface{}) error { + return ac.LegacyAmino.UnmarshalJSON(bz, ptr) +} diff --git a/codec/amino_codec_test.go b/codec/amino_codec_test.go index 6f17c092af9c..d9ccdb0496ed 100644 --- a/codec/amino_codec_test.go +++ b/codec/amino_codec_test.go @@ -28,6 +28,9 @@ func TestAminoMarsharlInterface(t *testing.T) { cdc := codec.NewAminoCodec(createTestCodec()) m := interfaceMarshaler{cdc.MarshalInterface, cdc.UnmarshalInterface} testInterfaceMarshaling(require.New(t), m, true) + + m = interfaceMarshaler{cdc.MarshalInterfaceJSON, cdc.UnmarshalInterfaceJSON} + testInterfaceMarshaling(require.New(t), m, false) } func TestAminoCodec(t *testing.T) { diff --git a/codec/codec.go b/codec/codec.go index a78c7010dc75..4746c58b6fae 100644 --- a/codec/codec.go +++ b/codec/codec.go @@ -41,8 +41,8 @@ type ( JSONMarshaler interface { MarshalJSON(o proto.Message) ([]byte, error) MustMarshalJSON(o proto.Message) []byte - // MarshalInterfaceJSON(i interface{}) ([]byte, error) - // UnmarshalInterfaceJSON(bz []byte, ptr interface{}) error + MarshalInterfaceJSON(i proto.Message) ([]byte, error) + UnmarshalInterfaceJSON(bz []byte, ptr interface{}) error UnmarshalJSON(bz []byte, ptr proto.Message) error MustUnmarshalJSON(bz []byte, ptr proto.Message) diff --git a/codec/codec_common_test.go b/codec/codec_common_test.go index f8680955b9e4..10820ecc5097 100644 --- a/codec/codec_common_test.go +++ b/codec/codec_common_test.go @@ -16,25 +16,27 @@ type interfaceMarshaler struct { unmarshal func(bz []byte, ptr interface{}) error } -func testInterfaceMarshaling(require *require.Assertions, cdc interfaceMarshaler, isAmino bool) { +func testInterfaceMarshaling(require *require.Assertions, cdc interfaceMarshaler, isAminoBin bool) { dog := &testdata.Dog{Name: "rufus"} var dogI testdata.Animal = dog bz, err := cdc.marshal(dogI) require.NoError(err) var animal testdata.Animal - if isAmino { + if isAminoBin { require.PanicsWithValue("Unmarshal expects a pointer", func() { cdc.unmarshal(bz, animal) }) } else { - require.EqualError(cdc.unmarshal(bz, animal), "UnpackAny expects a pointer") + err = cdc.unmarshal(bz, animal) + require.Error(err) + require.Contains(err.Error(), "expects a pointer") } require.NoError(cdc.unmarshal(bz, &animal)) require.Equal(dog, animal) // Amino doesn't wrap into Any, so it doesn't need to register self type - if isAmino { + if isAminoBin { var dog2 testdata.Dog require.NoError(cdc.unmarshal(bz, &dog2)) require.Equal(*dog, dog2) diff --git a/codec/proto_codec.go b/codec/proto_codec.go index f7fa05f10517..831e9b37d3f4 100644 --- a/codec/proto_codec.go +++ b/codec/proto_codec.go @@ -161,10 +161,9 @@ func (pc *ProtoCodec) MustUnmarshalJSON(bz []byte, ptr proto.Message) { } } -// MarshalInterface is a convenience function for proto marshalling interfaces. It -// packs the provided value, which must implement proto.Message, -// in an Any and then marshals it to bytes. -// NOTE: if you use a concrete type, then you should use MarshalBinaryBare instead +// MarshalInterface is a convenience function for proto marshalling interfaces. It packs +// the provided value, which must be an interface, in an Any and then marshals it to bytes. +// NOTE: to marshal a concrete type, you should use MarshalBinaryBare instead func (pc *ProtoCodec) MarshalInterface(i proto.Message) ([]byte, error) { if err := assertNotNil(i); err != nil { return nil, err @@ -180,7 +179,7 @@ func (pc *ProtoCodec) MarshalInterface(i proto.Message) ([]byte, error) { // UnmarshalInterface is a convenience function for proto unmarshaling interfaces. It // unmarshals an Any from bz bytes and then unpacks it to the `ptr`, which must // be a pointer to a non empty interface with registered implementations. -// NOTE: if you use a concert type, then you should use UnarshalBinaryBare instead +// NOTE: to unmarshal a concrete type, you should use UnarshalBinaryBare instead // // Example: // var x MyInterface @@ -197,7 +196,7 @@ func (pc *ProtoCodec) UnmarshalInterface(bz []byte, ptr interface{}) error { // MarshalInterfaceJSON is a convenience function for proto marshalling interfaces. It // packs the provided value in an Any and then marshals it to bytes. -// NOTE: if you use a conceret type, then you should use JSONMarshaler.MarshalJSON instead +// NOTE: to marshal a concrete type, you should use MarshalJSON instead func (pc *ProtoCodec) MarshalInterfaceJSON(x proto.Message) ([]byte, error) { any, err := types.NewAnyWithValue(x) if err != nil { @@ -209,11 +208,11 @@ func (pc *ProtoCodec) MarshalInterfaceJSON(x proto.Message) ([]byte, error) { // UnmarshalInterfaceJSON is a convenience function for proto unmarshaling interfaces. // It unmarshals an Any from bz bytes and then unpacks it to the `iface`, which must // be a pointer to a non empty interface, implementing proto.Message with registered implementations. -// NOTE: if you use a conceret type, then you should use JSONMarshaler.UnarshalJSON instead +// NOTE: to unmarshal a concrete type, you should use UnarshalJSON instead // // Example: // var x MyInterface // must implement proto.Message -// err := UnmarshalAny(unpacker, &x, bz) +// err := UnmarshalInterfaceJSON(unpacker, &x, bz) func (pc *ProtoCodec) UnmarshalInterfaceJSON(bz []byte, iface interface{}) error { any := &types.Any{} err := pc.UnmarshalJSON(bz, any)