Skip to content

Commit

Permalink
Fix Codec
Browse files Browse the repository at this point in the history
  • Loading branch information
SyntaxNode committed Feb 8, 2024
1 parent a93e96b commit dcf5e27
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 58 deletions.
4 changes: 2 additions & 2 deletions endpoints/openrtb2/auction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ func TestJsonSampleRequests(t *testing.T) {
},
}

jsoniter.RegisterExtension(&jsonutil.SampleExtension{})
jsoniter.RegisterExtension(&jsonutil.RawMessageExtension{})
for _, tc := range testSuites {
err := filepath.WalkDir(filepath.Join("sample-requests", tc.sampleRequestsSubDir), func(path string, info fs.DirEntry, err error) error {
// According to documentation, needed to avoid panics
Expand All @@ -145,7 +145,7 @@ func TestJsonSampleRequests(t *testing.T) {
}

func TestSingleJSONTest(t *testing.T) {
jsoniter.RegisterExtension(&jsonutil.SampleExtension{})
jsoniter.RegisterExtension(&jsonutil.RawMessageExtension{})
runJsonBasedTest(t, "sample-requests/valid-whole/exemplary/simple.json", "")
}

Expand Down
82 changes: 26 additions & 56 deletions util/jsonutil/jsonutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,11 @@ var jsonConfigValidationOff = jsoniter.Config{
ValidateJsonRawMessage: false,
}.Froze()

func init() {
jsonConfigValidationOff.RegisterExtension(&RawMessageExtension{})
jsonConfigValidationOn.RegisterExtension(&RawMessageExtension{})
}

// Unmarshal unmarshals a byte slice into the specified data structure without performing
// any validation on the data. An unmarshal error is returned if a non-validation error occurs.
func Unmarshal(data []byte, v interface{}) error {
Expand Down Expand Up @@ -214,72 +219,37 @@ func isLikelyDetailedErrorMessage(msg string) bool {
return !strings.HasPrefix(msg, "request.")
}

type wrapCodec struct {
encodeFunc func(ptr unsafe.Pointer, stream *jsoniter.Stream)
isEmptyFunc func(ptr unsafe.Pointer) bool
decodeFunc func(ptr unsafe.Pointer, iter *jsoniter.Iterator)
}
var jsonRawMessageType = reflect2.TypeOfPtr(&json.RawMessage{}).Elem()

func (codec *wrapCodec) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
codec.encodeFunc(ptr, stream)
// RawMessageExtension provides an encoder to compact json.RawMessage fields to match behavior
// of the encoding/json library.
type RawMessageExtension struct {
jsoniter.DummyExtension
}

func (codec *wrapCodec) IsEmpty(ptr unsafe.Pointer) bool {
if codec.isEmptyFunc == nil {
return false
func (e *RawMessageExtension) CreateEncoder(typ reflect2.Type) jsoniter.ValEncoder {
if typ == jsonRawMessageType {
return &rawMessageCodec{}
}

return codec.isEmptyFunc(ptr)
return nil
}

func (codec *wrapCodec) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
codec.decodeFunc(ptr, iter)
}
type rawMessageCodec struct{}

type SampleExtension struct {
jsoniter.DummyExtension
}
func (codec *rawMessageCodec) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
if ptr != nil {
jsonRawMsg := *(*[]byte)(ptr)

func (e *SampleExtension) CreateDecoder(typ reflect2.Type) jsoniter.ValDecoder {
if t, ok := typ.(*reflect2.UnsafePtrType); ok {
decoder := jsonConfigValidationOn.DecoderOf(t)
return &wrapCodec{
decodeFunc: decoder.Decode,
}
}
if _, ok := typ.(*reflect2.UnsafeStructType); ok {
return &wrapCodec{
decodeFunc: func(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
pObj := (*interface{})(ptr)
obj := *pObj
iter.ReadVal(&obj)

//str := *((*string)(ptr))
//r := strings.NewReader(str)
//decoder := jsonConfigValidationOn.NewDecoder(r)
//decoder.Decode(ptr)
},
dst := bytes.NewBuffer(make([]byte, 0, len(jsonRawMsg)))
if err := json.Compact(dst, jsonRawMsg); err != nil {
stream.Error = err
return
}

stream.Write(dst.Bytes())
}
return nil
}

func (e *SampleExtension) CreateEncoder(typ reflect2.Type) jsoniter.ValEncoder {
if typ.String() == "json.RawMessage" {
return &wrapCodec{
encodeFunc: func(ptr unsafe.Pointer, stream *jsoniter.Stream) {
if ptr != nil {
jsonRawMsg := *(*[]byte)(ptr)

dst := &bytes.Buffer{}
json.Compact(dst, jsonRawMsg)
stream.WriteStringWithHTMLEscaped(dst.String())
}
},
isEmptyFunc: func(ptr unsafe.Pointer) bool {
return *((*string)(ptr)) == ""
},
}
}
return nil
func (codec *rawMessageCodec) IsEmpty(ptr unsafe.Pointer) bool {
return *((*string)(ptr)) == ""
}
25 changes: 25 additions & 0 deletions util/jsonutil/jsonutil_test.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package jsonutil

import (
"encoding/json"
"errors"
"strings"
"testing"

jsoniter "github.com/json-iterator/go"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestDropElement(t *testing.T) {
Expand Down Expand Up @@ -240,3 +243,25 @@ func TestTryExtractErrorMessage(t *testing.T) {
})
}
}

func TestRawMessageExtension(t *testing.T) {
x := struct {
Raw json.RawMessage
}{
Raw: json.RawMessage(`{ "not" : "compact"}`),
}

// setup test
jsoniter.RegisterExtension(&RawMessageExtension{})

// encode
result, err := Marshal(x)
require.NoError(t, err)
require.Equal(t, `{"Raw":{"not":"compact"}}`, string(result))

// decode
err = Unmarshal(result, &x)
require.NoError(t, err)
assert.Equal(t, `{"not":"compact"}`, string(x.Raw))

}

0 comments on commit dcf5e27

Please sign in to comment.