Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix pointer marshal #56

Merged
merged 2 commits into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions sheriff.go
Original file line number Diff line number Diff line change
Expand Up @@ -282,10 +282,21 @@ func marshalValue(options *Options, v reflect.Value) (interface{}, error) {
// types which are e.g. structs, slices or maps and implement one of the following interfaces should not be
// marshalled by sheriff because they'll be correctly marshalled by json.Marshal instead.
// Otherwise (e.g. net.IP) a byte slice may be output as a list of uints instead of as an IP string.
// This needs to be checked for both value and pointer types.
switch val.(type) {
case json.Marshaler, encoding.TextMarshaler, fmt.Stringer:
return val, nil
}

if v.CanAddr() {
addrVal := v.Addr().Interface()

switch addrVal.(type) {
case json.Marshaler, encoding.TextMarshaler, fmt.Stringer:
return addrVal, nil
}
}

k := v.Kind()

switch k {
Expand Down
41 changes: 38 additions & 3 deletions sheriff_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package sheriff

import (
"encoding/json"
"fmt"
"net"
"reflect"
"testing"
Expand Down Expand Up @@ -579,14 +580,46 @@ type TestMarshal_Embedded struct {
Foo string `json:"foo" groups:"test"`
}

// TestMarshal_EmbeddedCustom is used to test an embedded struct with a custom marshaler that is not a pointer.
type TestMarshal_EmbeddedCustom struct {
Val int
Set bool
}

func (t TestMarshal_EmbeddedCustom) MarshalJSON() ([]byte, error) {
if t.Set {
return []byte(fmt.Sprintf("%d", t.Val)), nil
}

return nil, nil
}

// TestMarshal_EmbeddedCustomPtr is used to test an embedded struct with a custom marshaler that is a pointer.
type TestMarshal_EmbeddedCustomPtr struct {
Val int
Set bool
}

func (t *TestMarshal_EmbeddedCustomPtr) MarshalJSON() ([]byte, error) {
if t.Set {
return []byte(fmt.Sprintf("%d", t.Val)), nil
}

return nil, nil
}

type TestMarshal_EmbeddedParent struct {
*TestMarshal_Embedded
Bar string `json:"bar" groups:"test"`
*TestMarshal_EmbeddedCustom `json:"value"`
*TestMarshal_EmbeddedCustomPtr `json:"value_ptr"`
Bar string `json:"bar" groups:"test"`
}

func TestMarshal_EmbeddedField(t *testing.T) {
v := TestMarshal_EmbeddedParent{
&TestMarshal_Embedded{"Hello"},
&TestMarshal_EmbeddedCustom{10, true},
&TestMarshal_EmbeddedCustomPtr{20, true},
"World",
}
o := &Options{Groups: []string{"test"}}
Expand All @@ -598,8 +631,10 @@ func TestMarshal_EmbeddedField(t *testing.T) {
assert.NoError(t, err)

expected, err := json.Marshal(map[string]interface{}{
"bar": "World",
"foo": "Hello",
"bar": "World",
"foo": "Hello",
"value": 10,
"value_ptr": 20,
})
assert.NoError(t, err)

Expand Down
Loading