Skip to content
This repository was archived by the owner on Dec 4, 2019. It is now read-only.
Open
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
23 changes: 23 additions & 0 deletions decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package objconv

import (
"encoding"
"encoding/json"
"errors"
"fmt"
"reflect"
Expand Down Expand Up @@ -946,6 +947,22 @@ func (d Decoder) decodeTextUnmarshaler(to reflect.Value) (t Type, err error) {
return
}

func (d Decoder) decodeJSONUnmarshaler(to reflect.Value) (t Type, err error) {
var s string
var v = reflect.ValueOf(&s).Elem()

if t, err = d.decodeString(v); err != nil {
return
}

if to.Kind() == reflect.Ptr && to.IsNil() {
to.Set(reflect.New(to.Type().Elem()))
}

err = to.Interface().(json.Unmarshaler).UnmarshalJSON([]byte(s))
return
}

func (d Decoder) decodeInterface(to reflect.Value) (t Type, err error) {
if t, err = d.Parser.ParseType(); err == nil {
err = d.decodeInterfaceFromType(t, to)
Expand Down Expand Up @@ -1391,6 +1408,9 @@ func makeDecodeFunc(t reflect.Type, opts decodeFuncOpts) decodeFunc {

case t.Implements(textUnmarshalerInterface):
return Decoder.decodeTextUnmarshaler

case t.Implements(jsonDecoderInterface):
return Decoder.decodeJSONUnmarshaler
}

switch p := reflect.PtrTo(t); {
Expand All @@ -1405,6 +1425,9 @@ func makeDecodeFunc(t reflect.Type, opts decodeFuncOpts) decodeFunc {

case p.Implements(textUnmarshalerInterface):
return Decoder.decodeTextUnmarshalerPointer

case p.Implements(jsonDecoderInterface):
return Decoder.decodeJSONUnmarshaler
}

// check what kind is the type, potentially generate a decoder
Expand Down
15 changes: 15 additions & 0 deletions decode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import (
)

func TestDecoderDecodeType(t *testing.T) {
// var ex exampleJSONUnmarshaler
// json.Unmarshaler(&ex).UnmarshalJSON([]byte("2"))

date := time.Date(2016, 12, 12, 01, 01, 01, 0, time.UTC)
err := errors.New("error")

Expand Down Expand Up @@ -217,6 +220,9 @@ func TestDecoderDecodeType(t *testing.T) {

// struct -> ptr
{struct{ A int }{42}, &struct{ A int }{42}},

// bytes -> json unmarshaler
{"fake json", &exampleJSONUnmarshaler{[]byte("fake json")}},
}

for _, test := range tests {
Expand Down Expand Up @@ -402,3 +408,12 @@ func TestStreamRencode(t *testing.T) {
})
}
}

type exampleJSONUnmarshaler struct {
b []byte
}

func (ex *exampleJSONUnmarshaler) UnmarshalJSON(b []byte) error {
ex.b = b
return nil
}
12 changes: 12 additions & 0 deletions encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package objconv

import (
"encoding"
"encoding/json"
"fmt"
"io"
"reflect"
Expand Down Expand Up @@ -464,6 +465,14 @@ func (e Encoder) encodeTextMarshaler(v reflect.Value) error {
return err
}

func (e Encoder) encodeJSONMarshaler(v reflect.Value) error {
b, err := v.Interface().(json.Marshaler).MarshalJSON()
if err == nil {
err = e.Emitter.EmitString(stringNoCopy(b))
}
return err
}

func (e Encoder) encodeUnsupported(v reflect.Value) error {
return fmt.Errorf("objconv: the encoder doesn't support values of type %s", v.Type())
}
Expand Down Expand Up @@ -764,6 +773,9 @@ func makeEncodeFunc(t reflect.Type, opts encodeFuncOpts) encodeFunc {

case t.Implements(errorInterface):
return Encoder.encodeError

case t.Implements(jsonEncoderInterface):
return Encoder.encodeJSONMarshaler
}

switch t.Kind() {
Expand Down
11 changes: 11 additions & 0 deletions encode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ type TFloat64 float64
type TString string
type TBytes []byte

type exampleJSONMarshaler struct {
b []byte
}

func (ex *exampleJSONMarshaler) MarshalJSON() ([]byte, error) {
return ex.b, nil
}

func TestEncoder(t *testing.T) {
now := time.Now()
err := errors.New("error")
Expand Down Expand Up @@ -163,6 +171,9 @@ func TestEncoder(t *testing.T) {
},
},
},

// json marshaler -> bytes
{&exampleJSONMarshaler{b: []byte("fake json")}, "fake json"},
}

for _, test := range tests {
Expand Down
3 changes: 3 additions & 0 deletions value.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package objconv

import (
"encoding"
"encoding/json"
"errors"
"reflect"
"sync"
Expand Down Expand Up @@ -108,6 +109,8 @@ var (

// interfaces
errorInterface = elemTypeOf((*error)(nil))
jsonDecoderInterface = elemTypeOf((*json.Unmarshaler)(nil))
jsonEncoderInterface = elemTypeOf((*json.Marshaler)(nil))
valueEncoderInterface = elemTypeOf((*ValueEncoder)(nil))
valueDecoderInterface = elemTypeOf((*ValueDecoder)(nil))
binaryMarshalerInterface = elemTypeOf((*encoding.BinaryMarshaler)(nil))
Expand Down