1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465 |
- package formatter
- import (
- "encoding/json"
- "fmt"
- "reflect"
- "unicode"
- )
- func marshalJSON(x interface{}) ([]byte, error) {
- m, err := marshalMap(x)
- if err != nil {
- return nil, err
- }
- return json.Marshal(m)
- }
- // marshalMap marshals x to map[string]interface{}
- func marshalMap(x interface{}) (map[string]interface{}, error) {
- val := reflect.ValueOf(x)
- if val.Kind() != reflect.Ptr {
- return nil, fmt.Errorf("expected a pointer to a struct, got %v", val.Kind())
- }
- if val.IsNil() {
- return nil, fmt.Errorf("expxected a pointer to a struct, got nil pointer")
- }
- valElem := val.Elem()
- if valElem.Kind() != reflect.Struct {
- return nil, fmt.Errorf("expected a pointer to a struct, got a pointer to %v", valElem.Kind())
- }
- typ := val.Type()
- m := make(map[string]interface{})
- for i := 0; i < val.NumMethod(); i++ {
- k, v, err := marshalForMethod(typ.Method(i), val.Method(i))
- if err != nil {
- return nil, err
- }
- if k != "" {
- m[k] = v
- }
- }
- return m, nil
- }
- var unmarshallableNames = map[string]struct{}{"FullHeader": {}}
- // marshalForMethod returns the map key and the map value for marshalling the method.
- // It returns ("", nil, nil) for valid but non-marshallable parameter. (e.g. "unexportedFunc()")
- func marshalForMethod(typ reflect.Method, val reflect.Value) (string, interface{}, error) {
- if val.Kind() != reflect.Func {
- return "", nil, fmt.Errorf("expected func, got %v", val.Kind())
- }
- name, numIn, numOut := typ.Name, val.Type().NumIn(), val.Type().NumOut()
- _, blackListed := unmarshallableNames[name]
- // FIXME: In text/template, (numOut == 2) is marshallable,
- // if the type of the second param is error.
- marshallable := unicode.IsUpper(rune(name[0])) && !blackListed &&
- numIn == 0 && numOut == 1
- if !marshallable {
- return "", nil, nil
- }
- result := val.Call(make([]reflect.Value, numIn))
- intf := result[0].Interface()
- return name, intf, nil
- }
|