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
4 changed files with 100 additions and 30 deletions
|
@ -20,8 +20,12 @@ func (c *Context) Ref() Ref {
|
||||||
func (r *Ref) MarshalText() ([]byte, error) {
|
func (r *Ref) MarshalText() ([]byte, error) {
|
||||||
return []byte(*r), nil
|
return []byte(*r), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) MarshalJSON() ([]byte, error) {
|
func (c *Context) MarshalJSON() ([]byte, error) {
|
||||||
var a map[string]interface{}
|
a := reflectToJsonValue(c)
|
||||||
a = reflectToJsonLdMap(c)
|
if a.isScalar {
|
||||||
return json.Marshal(a)
|
return json.Marshal(a.scalar)
|
||||||
|
} else {
|
||||||
|
return json.Marshal(a.object)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package jsonld
|
package jsonld
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"activitypub"
|
||||||
"bytes"
|
"bytes"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"activitypub"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRef_MarshalText(t *testing.T) {
|
func TestRef_MarshalText(t *testing.T) {
|
||||||
|
|
|
@ -49,14 +49,46 @@ func isEmptyValue(v reflect.Value) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func reflectToJsonLdMap(v interface{}) map[string]interface{} {
|
type jsonCapableValue struct {
|
||||||
a := make(map[string]interface{})
|
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)
|
typ := reflect.TypeOf(v)
|
||||||
val := reflect.ValueOf(v)
|
val := reflect.ValueOf(v)
|
||||||
if typ.Kind() == reflect.Ptr {
|
if typ.Kind() == reflect.Ptr {
|
||||||
typ = typ.Elem()
|
typ = typ.Elem()
|
||||||
val = val.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++ {
|
for i := 0; i < typ.NumField(); i++ {
|
||||||
cField := typ.Field(i)
|
cField := typ.Field(i)
|
||||||
|
@ -69,14 +101,17 @@ func reflectToJsonLdMap(v interface{}) map[string]interface{} {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if cField.Anonymous {
|
if cField.Anonymous {
|
||||||
for k, v := range reflectToJsonLdMap(cValue.Interface()) {
|
anonJsonVal := reflectToJsonValue(cValue.Interface())
|
||||||
a[k] = v
|
if anonJsonVal.isScalar {
|
||||||
}
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
for k, v := range anonJsonVal.object {
|
||||||
|
a.object[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
empty := isEmptyValue(cValue)
|
empty := isEmptyValue(cValue)
|
||||||
if !empty || empty && !omitEmpty {
|
if !empty || empty && !omitEmpty {
|
||||||
a[jsonLdName(cField.Name, jsonLdTag)] = cValue.Interface()
|
a.object[jsonLdName(cField.Name, jsonLdTag)] = cValue.Interface()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,37 +119,49 @@ func reflectToJsonLdMap(v interface{}) map[string]interface{} {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *payloadWithContext) MarshalJSON() ([]byte, error) {
|
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 {
|
if p.Context != nil {
|
||||||
|
a.isScalar = false
|
||||||
typ := reflect.TypeOf(*p)
|
typ := reflect.TypeOf(*p)
|
||||||
cMirror, _ := typ.FieldByName("Context")
|
cMirror, _ := typ.FieldByName("Context")
|
||||||
jsonLdTag, ok := loadJsonLdTag(cMirror.Tag)
|
jsonLdTag, ok := loadJsonLdTag(cMirror.Tag)
|
||||||
omitEmpty := ok && jsonLdTag.omitEmpty
|
omitEmpty := ok && jsonLdTag.omitEmpty
|
||||||
collapsible := ok && jsonLdTag.collapsible
|
collapsible := ok && jsonLdTag.collapsible
|
||||||
|
|
||||||
con := reflectToJsonLdMap(p.Context)
|
con := reflectToJsonValue(p.Context)
|
||||||
if len(con) > 0 || !omitEmpty {
|
if len(con.object) > 0 || !omitEmpty {
|
||||||
for _, v := range con {
|
for _, v := range con.object {
|
||||||
a[jsonLdName(cMirror.Name, jsonLdTag)] = v
|
a.object[jsonLdName(cMirror.Name, jsonLdTag)] = v
|
||||||
if len(con) == 1 && collapsible {
|
if len(con.object) == 1 && collapsible {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if *p.Obj != nil {
|
if p.Obj != nil {
|
||||||
oMap := reflectToJsonLdMap(*p.Obj)
|
oMap := reflectToJsonValue(*p.Obj)
|
||||||
if len(oMap) == 0 {
|
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")
|
return nil, fmt.Errorf("invalid object to marshall")
|
||||||
|
} else {
|
||||||
|
a.isScalar = false
|
||||||
}
|
}
|
||||||
for k, v := range oMap {
|
for k, v := range oMap.object {
|
||||||
a[k] = v
|
a.object[k] = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return json.Marshal(a)
|
|
||||||
}
|
}
|
||||||
|
if a.isScalar {
|
||||||
func (p *payloadWithContext) UnmarshalJSON() {}
|
return json.Marshal(a.scalar)
|
||||||
|
} else {
|
||||||
|
return json.Marshal(a.object)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type Encoder struct{}
|
type Encoder struct{}
|
||||||
|
|
||||||
|
|
|
@ -118,8 +118,27 @@ func TestIsEmpty(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPayloadWithContext_MarshalJSON(t *testing.T) {
|
func TestPayloadWithContext_MarshalJSON(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)
|
||||||
}
|
}
|
||||||
func TestPayloadWithContext_UnmarshalJSON(t *testing.T) {
|
|
||||||
t.Skipf("Not implemented")
|
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue