Skip to content

Commit

Permalink
add support for *JSON methods
Browse files Browse the repository at this point in the history
  • Loading branch information
robert-zaremba committed Dec 4, 2020
1 parent 247c730 commit 1bc30f9
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 21 deletions.
35 changes: 28 additions & 7 deletions codec/amino_codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,23 +81,44 @@ 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
}
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)
}
3 changes: 3 additions & 0 deletions codec/amino_codec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
4 changes: 2 additions & 2 deletions codec/codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
10 changes: 6 additions & 4 deletions codec/codec_common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
15 changes: 7 additions & 8 deletions codec/proto_codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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 {
Expand All @@ -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)
Expand Down

0 comments on commit 1bc30f9

Please sign in to comment.