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:
parent
b2d595e31d
commit
9d9bd8510b
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package jsonld
|
||||
|
||||
import (
|
||||
"activitypub"
|
||||
"bytes"
|
||||
"strings"
|
||||
"testing"
|
||||
"activitypub"
|
||||
)
|
||||
|
||||
func TestRef_MarshalText(t *testing.T) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
Reference in a new issue