Added a method for marshalling interface{}s which decay to scalars

for the moment it's overcomplicted and ugly

Moved UnmarshalJSON to decode.go file

Adding tests for some of the new functionality
This commit is contained in:
Marius Orcsik 2017-10-02 17:24:26 +02:00
parent b2d595e31d
commit 9d9bd8510b
No known key found for this signature in database
GPG key ID: C36D1EBE93A6EEAE
4 changed files with 100 additions and 30 deletions

View file

@ -20,8 +20,12 @@ func (c *Context) Ref() Ref {
func (r *Ref) MarshalText() ([]byte, error) {
return []byte(*r), nil
}
func (c *Context) MarshalJSON() ([]byte, error) {
var a map[string]interface{}
a = reflectToJsonLdMap(c)
return json.Marshal(a)
a := reflectToJsonValue(c)
if a.isScalar {
return json.Marshal(a.scalar)
} else {
return json.Marshal(a.object)
}
}

View file

@ -1,10 +1,10 @@
package jsonld
import (
"activitypub"
"bytes"
"strings"
"testing"
"activitypub"
)
func TestRef_MarshalText(t *testing.T) {

View file

@ -49,14 +49,46 @@ func isEmptyValue(v reflect.Value) bool {
return false
}
func reflectToJsonLdMap(v interface{}) map[string]interface{} {
a := make(map[string]interface{})
type jsonCapableValue struct {
isScalar bool
scalar interface{}
object map[string]interface{}
}
func reflectToJsonValue(v interface{}) jsonCapableValue {
a := jsonCapableValue{}
a.object = make(map[string]interface{})
typ := reflect.TypeOf(v)
val := reflect.ValueOf(v)
if typ.Kind() == reflect.Ptr {
typ = typ.Elem()
val = val.Elem()
}
switch typ.Kind() {
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
a.scalar = val.Interface()
a.isScalar = true
return a
case reflect.Bool:
a.scalar = val.Bool()
a.isScalar = true
return a
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
a.scalar = val.Int()
a.isScalar = true
return a
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
a.scalar = val.Uint()
a.isScalar = true
return a
case reflect.Float32, reflect.Float64:
a.scalar = val.Float()
a.isScalar = true
return a
case reflect.Interface, reflect.Ptr:
a.isScalar = true
return a
}
for i := 0; i < typ.NumField(); i++ {
cField := typ.Field(i)
@ -69,14 +101,17 @@ func reflectToJsonLdMap(v interface{}) map[string]interface{} {
continue
}
if cField.Anonymous {
for k, v := range reflectToJsonLdMap(cValue.Interface()) {
a[k] = v
anonJsonVal := reflectToJsonValue(cValue.Interface())
if anonJsonVal.isScalar {
continue
}
for k, v := range anonJsonVal.object {
a.object[k] = v
}
continue
}
empty := isEmptyValue(cValue)
if !empty || empty && !omitEmpty {
a[jsonLdName(cField.Name, jsonLdTag)] = cValue.Interface()
a.object[jsonLdName(cField.Name, jsonLdTag)] = cValue.Interface()
}
}
@ -84,38 +119,50 @@ func reflectToJsonLdMap(v interface{}) map[string]interface{} {
}
func (p *payloadWithContext) MarshalJSON() ([]byte, error) {
a := make(map[string]interface{})
a := jsonCapableValue{}
a.isScalar = true
a.object = make(map[string]interface{})
if p.Context != nil {
a.isScalar = false
typ := reflect.TypeOf(*p)
cMirror, _ := typ.FieldByName("Context")
jsonLdTag, ok := loadJsonLdTag(cMirror.Tag)
omitEmpty := ok && jsonLdTag.omitEmpty
collapsible := ok && jsonLdTag.collapsible
con := reflectToJsonLdMap(p.Context)
if len(con) > 0 || !omitEmpty {
for _, v := range con {
a[jsonLdName(cMirror.Name, jsonLdTag)] = v
if len(con) == 1 && collapsible {
con := reflectToJsonValue(p.Context)
if len(con.object) > 0 || !omitEmpty {
for _, v := range con.object {
a.object[jsonLdName(cMirror.Name, jsonLdTag)] = v
if len(con.object) == 1 && collapsible {
break
}
}
}
}
if *p.Obj != nil {
oMap := reflectToJsonLdMap(*p.Obj)
if len(oMap) == 0 {
return nil, fmt.Errorf("invalid object to marshall")
}
for k, v := range oMap {
a[k] = v
if p.Obj != nil {
oMap := reflectToJsonValue(*p.Obj)
if oMap.isScalar && a.isScalar {
a.isScalar = true
a.scalar = oMap.scalar
} else {
if len(oMap.object) == 0 {
return nil, fmt.Errorf("invalid object to marshall")
} else {
a.isScalar = false
}
for k, v := range oMap.object {
a.object[k] = v
}
}
}
return json.Marshal(a)
if a.isScalar {
return json.Marshal(a.scalar)
} else {
return json.Marshal(a.object)
}
}
func (p *payloadWithContext) UnmarshalJSON() {}
type Encoder struct{}
type jsonLdTag struct {

View file

@ -118,8 +118,27 @@ func TestIsEmpty(t *testing.T) {
}
func TestPayloadWithContext_MarshalJSON(t *testing.T) {
t.Skipf("Not implemented")
}
func TestPayloadWithContext_UnmarshalJSON(t *testing.T) {
t.Skipf("Not implemented")
empty := payloadWithContext{}
eData, eErr := empty.MarshalJSON()
if eErr != nil {
t.Errorf("Error: %s", eErr)
}
n, _ := json.Marshal(nil)
if bytes.Compare(eData, n) != 0 {
t.Errorf("Empty payload should resolve to null json value '%s', received '%s'", n, eData)
}
var a interface{}
a = 1
p := payloadWithContext{Obj: &a}
pData, pErr := p.MarshalJSON()
if pErr != nil {
t.Errorf("Error: %s", pErr)
}
av, _ := json.Marshal(a)
if bytes.Compare(pData, av) != 0 {
t.Errorf("Empty payload should resolve to value '%#v', received '%s'", av, pData)
}
}