blob: a5a28c5d3075b5fa33ba05b84eceb4c320e4984d [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package util
import (
"encoding/json"
"fmt"
"reflect"
"strings"
)
import (
"github.com/apache/dubbo-go-pixiu/pixiu/pkg/client"
)
func NewDubboResponse(data interface{}, hump bool) *client.Response {
r, _ := dealResp(data, hump)
bytes, _ := json.Marshal(r)
return &client.Response{Data: bytes}
}
func dealResp(in interface{}, HumpToLine bool) (interface{}, error) {
if in == nil {
return in, nil
}
switch reflect.TypeOf(in).Kind() {
case reflect.Map:
if _, ok := in.(map[interface{}]interface{}); ok {
m := mapIItoMapSI(in)
if HumpToLine {
m = humpToLine(m)
}
return m, nil
} else if inm, ok := in.(map[string]interface{}); ok {
if HumpToLine {
m := humpToLine(in)
return m, nil
}
return inm, nil
}
case reflect.Slice:
if data, ok := in.([]byte); ok {
// raw bytes data should return directly
return data, nil
}
value := reflect.ValueOf(in)
newTemps := make([]interface{}, 0, value.Len())
for i := 0; i < value.Len(); i++ {
if value.Index(i).CanInterface() {
newTemp, e := dealResp(value.Index(i).Interface(), HumpToLine)
if e != nil {
return nil, e
}
newTemps = append(newTemps, newTemp)
} else {
return nil, fmt.Errorf("unexpect err,value:%v", value)
}
}
return newTemps, nil
default:
return in, nil
}
return in, nil
}
func mapIItoMapSI(in interface{}) interface{} {
var inMap map[interface{}]interface{}
if v, ok := in.(map[interface{}]interface{}); !ok {
return in
} else {
inMap = v
}
outMap := make(map[string]interface{}, len(inMap))
for k, v := range inMap {
if v == nil {
continue
}
s := fmt.Sprint(k)
if s == "class" {
// ignore the "class" field
continue
}
vt := reflect.TypeOf(v)
switch vt.Kind() {
case reflect.Map:
if _, ok := v.(map[interface{}]interface{}); ok {
v = mapIItoMapSI(v)
}
case reflect.Slice:
vl := reflect.ValueOf(v)
os := make([]interface{}, 0, vl.Len())
for i := 0; i < vl.Len(); i++ {
if vl.Index(i).CanInterface() {
osv := mapIItoMapSI(vl.Index(i).Interface())
os = append(os, osv)
}
}
v = os
}
outMap[s] = v
}
return outMap
}
// traverse all the keys in the map and change the hump to underline
func humpToLine(in interface{}) interface{} {
var m map[string]interface{}
if v, ok := in.(map[string]interface{}); ok {
m = v
} else {
return in
}
out := make(map[string]interface{}, len(m))
for k1, v1 := range m {
x := humpToUnderline(k1)
if v1 == nil {
out[x] = v1
} else if reflect.TypeOf(v1).Kind() == reflect.Struct {
out[x] = humpToLine(struct2Map(v1))
} else if reflect.TypeOf(v1).Kind() == reflect.Slice {
value := reflect.ValueOf(v1)
newTemps := make([]interface{}, 0, value.Len())
for i := 0; i < value.Len(); i++ {
newTemp := humpToLine(value.Index(i).Interface())
newTemps = append(newTemps, newTemp)
}
out[x] = newTemps
} else if reflect.TypeOf(v1).Kind() == reflect.Map {
out[x] = humpToLine(v1)
} else {
out[x] = v1
}
}
return out
}
func humpToUnderline(s string) string {
data := make([]byte, 0, len(s)*2)
j := false
num := len(s)
for i := 0; i < num; i++ {
d := s[i]
if i > 0 && d >= 'A' && d <= 'Z' && j {
data = append(data, '_')
}
if d != '_' {
j = true
}
data = append(data, d)
}
return strings.ToLower(string(data[:]))
}
func struct2Map(obj interface{}) map[string]interface{} {
t := reflect.TypeOf(obj)
v := reflect.ValueOf(obj)
data := make(map[string]interface{})
for i := 0; i < t.NumField(); i++ {
data[t.Field(i).Name] = v.Field(i).Interface()
}
return data
}