|
Packit Service |
3a6627 |
package jsoninfo
|
|
Packit Service |
3a6627 |
|
|
Packit Service |
3a6627 |
import (
|
|
Packit Service |
3a6627 |
"encoding/json"
|
|
Packit Service |
3a6627 |
"fmt"
|
|
Packit Service |
3a6627 |
"reflect"
|
|
Packit Service |
3a6627 |
)
|
|
Packit Service |
3a6627 |
|
|
Packit Service |
3a6627 |
// UnmarshalStrictStruct function:
|
|
Packit Service |
3a6627 |
// * Unmarshals struct fields, ignoring UnmarshalJSON(...) and fields without 'json' tag.
|
|
Packit Service |
3a6627 |
// * Correctly handles StrictStruct
|
|
Packit Service |
3a6627 |
func UnmarshalStrictStruct(data []byte, value StrictStruct) error {
|
|
Packit Service |
3a6627 |
decoder, err := NewObjectDecoder(data)
|
|
Packit Service |
3a6627 |
if err != nil {
|
|
Packit Service |
3a6627 |
return err
|
|
Packit Service |
3a6627 |
}
|
|
Packit Service |
3a6627 |
return value.DecodeWith(decoder, value)
|
|
Packit Service |
3a6627 |
}
|
|
Packit Service |
3a6627 |
|
|
Packit Service |
3a6627 |
type ObjectDecoder struct {
|
|
Packit Service |
3a6627 |
Data []byte
|
|
Packit Service |
3a6627 |
remainingFields map[string]json.RawMessage
|
|
Packit Service |
3a6627 |
}
|
|
Packit Service |
3a6627 |
|
|
Packit Service |
3a6627 |
func NewObjectDecoder(data []byte) (*ObjectDecoder, error) {
|
|
Packit Service |
3a6627 |
var remainingFields map[string]json.RawMessage
|
|
Packit Service |
3a6627 |
if err := json.Unmarshal(data, &remainingFields); err != nil {
|
|
Packit Service |
3a6627 |
return nil, fmt.Errorf("Failed to unmarshal extension properties: %v\nInput: %s", err, data)
|
|
Packit Service |
3a6627 |
}
|
|
Packit Service |
3a6627 |
return &ObjectDecoder{
|
|
Packit Service |
3a6627 |
Data: data,
|
|
Packit Service |
3a6627 |
remainingFields: remainingFields,
|
|
Packit Service |
3a6627 |
}, nil
|
|
Packit Service |
3a6627 |
}
|
|
Packit Service |
3a6627 |
|
|
Packit Service |
3a6627 |
// DecodeExtensionMap returns all properties that were not decoded previously.
|
|
Packit Service |
3a6627 |
func (decoder *ObjectDecoder) DecodeExtensionMap() map[string]json.RawMessage {
|
|
Packit Service |
3a6627 |
return decoder.remainingFields
|
|
Packit Service |
3a6627 |
}
|
|
Packit Service |
3a6627 |
|
|
Packit Service |
3a6627 |
func (decoder *ObjectDecoder) DecodeStructFieldsAndExtensions(value interface{}) error {
|
|
Packit Service |
3a6627 |
reflection := reflect.ValueOf(value)
|
|
Packit Service |
3a6627 |
if reflection.Kind() != reflect.Ptr {
|
|
Packit Service |
3a6627 |
panic(fmt.Errorf("Value %T is not a pointer", value))
|
|
Packit Service |
3a6627 |
}
|
|
Packit Service |
3a6627 |
if reflection.IsNil() {
|
|
Packit Service |
3a6627 |
panic(fmt.Errorf("Value %T is nil", value))
|
|
Packit Service |
3a6627 |
}
|
|
Packit Service |
3a6627 |
reflection = reflection.Elem()
|
|
Packit Service |
3a6627 |
for (reflection.Kind() == reflect.Interface || reflection.Kind() == reflect.Ptr) && !reflection.IsNil() {
|
|
Packit Service |
3a6627 |
reflection = reflection.Elem()
|
|
Packit Service |
3a6627 |
}
|
|
Packit Service |
3a6627 |
reflectionType := reflection.Type()
|
|
Packit Service |
3a6627 |
if reflectionType.Kind() != reflect.Struct {
|
|
Packit Service |
3a6627 |
panic(fmt.Errorf("Value %T is not a struct", value))
|
|
Packit Service |
3a6627 |
}
|
|
Packit Service |
3a6627 |
typeInfo := GetTypeInfo(reflectionType)
|
|
Packit Service |
3a6627 |
|
|
Packit Service |
3a6627 |
// Supported fields
|
|
Packit Service |
3a6627 |
fields := typeInfo.Fields
|
|
Packit Service |
3a6627 |
remainingFields := decoder.remainingFields
|
|
Packit Service |
3a6627 |
for fieldIndex, field := range fields {
|
|
Packit Service |
3a6627 |
// Fields without JSON tag are ignored
|
|
Packit Service |
3a6627 |
if !field.HasJSONTag {
|
|
Packit Service |
3a6627 |
continue
|
|
Packit Service |
3a6627 |
}
|
|
Packit Service |
3a6627 |
|
|
Packit Service |
3a6627 |
// Get data
|
|
Packit Service |
3a6627 |
fieldData, exists := remainingFields[field.JSONName]
|
|
Packit Service |
3a6627 |
if !exists {
|
|
Packit Service |
3a6627 |
continue
|
|
Packit Service |
3a6627 |
}
|
|
Packit Service |
3a6627 |
|
|
Packit Service |
3a6627 |
// Unmarshal
|
|
Packit Service |
3a6627 |
if field.TypeIsUnmarshaller {
|
|
Packit Service |
3a6627 |
fieldType := field.Type
|
|
Packit Service |
3a6627 |
isPtr := false
|
|
Packit Service |
3a6627 |
if fieldType.Kind() == reflect.Ptr {
|
|
Packit Service |
3a6627 |
fieldType = fieldType.Elem()
|
|
Packit Service |
3a6627 |
isPtr = true
|
|
Packit Service |
3a6627 |
}
|
|
Packit Service |
3a6627 |
fieldValue := reflect.New(fieldType)
|
|
Packit Service |
3a6627 |
if err := fieldValue.Interface().(json.Unmarshaler).UnmarshalJSON(fieldData); err != nil {
|
|
Packit Service |
3a6627 |
if field.MultipleFields {
|
|
Packit Service |
3a6627 |
i := fieldIndex + 1
|
|
Packit Service |
3a6627 |
if i < len(fields) && fields[i].JSONName == field.JSONName {
|
|
Packit Service |
3a6627 |
continue
|
|
Packit Service |
3a6627 |
}
|
|
Packit Service |
3a6627 |
}
|
|
Packit Service |
3a6627 |
return fmt.Errorf("Error while unmarshalling property '%s' (%s): %v",
|
|
Packit Service |
3a6627 |
field.JSONName, fieldValue.Type().String(), err)
|
|
Packit Service |
3a6627 |
}
|
|
Packit Service |
3a6627 |
if !isPtr {
|
|
Packit Service |
3a6627 |
fieldValue = fieldValue.Elem()
|
|
Packit Service |
3a6627 |
}
|
|
Packit Service |
3a6627 |
reflection.FieldByIndex(field.Index).Set(fieldValue)
|
|
Packit Service |
3a6627 |
|
|
Packit Service |
3a6627 |
// Remove the field from remaining fields
|
|
Packit Service |
3a6627 |
delete(remainingFields, field.JSONName)
|
|
Packit Service |
3a6627 |
} else {
|
|
Packit Service |
3a6627 |
fieldPtr := reflection.FieldByIndex(field.Index)
|
|
Packit Service |
3a6627 |
if fieldPtr.Kind() != reflect.Ptr || fieldPtr.IsNil() {
|
|
Packit Service |
3a6627 |
fieldPtr = fieldPtr.Addr()
|
|
Packit Service |
3a6627 |
}
|
|
Packit Service |
3a6627 |
if err := json.Unmarshal(fieldData, fieldPtr.Interface()); err != nil {
|
|
Packit Service |
3a6627 |
if field.MultipleFields {
|
|
Packit Service |
3a6627 |
i := fieldIndex + 1
|
|
Packit Service |
3a6627 |
if i < len(fields) && fields[i].JSONName == field.JSONName {
|
|
Packit Service |
3a6627 |
continue
|
|
Packit Service |
3a6627 |
}
|
|
Packit Service |
3a6627 |
}
|
|
Packit Service |
3a6627 |
return fmt.Errorf("Error while unmarshalling property '%s' (%s): %v",
|
|
Packit Service |
3a6627 |
field.JSONName, fieldPtr.Type().String(), err)
|
|
Packit Service |
3a6627 |
}
|
|
Packit Service |
3a6627 |
|
|
Packit Service |
3a6627 |
// Remove the field from remaining fields
|
|
Packit Service |
3a6627 |
delete(remainingFields, field.JSONName)
|
|
Packit Service |
3a6627 |
}
|
|
Packit Service |
3a6627 |
}
|
|
Packit Service |
3a6627 |
return nil
|
|
Packit Service |
3a6627 |
}
|