From 96f5554a4c8b45ca08c25b834b74534a5e5959a6 Mon Sep 17 00:00:00 2001
From: pantianying <601666418@qq.com>
Date: Tue, 30 Jul 2019 18:03:24 +0800
Subject: [PATCH] add generic filter

---
 common/constant/default.go    |  2 +
 config/reference_config.go    |  2 +-
 filter/impl/generic_filter.go | 75 +++++++++++++++++++++++++++++++++++
 3 files changed, 78 insertions(+), 1 deletion(-)
 create mode 100644 filter/impl/generic_filter.go

diff --git a/common/constant/default.go b/common/constant/default.go
index 05461ca6e..7ab92249a 100644
--- a/common/constant/default.go
+++ b/common/constant/default.go
@@ -38,6 +38,8 @@ const (
 	PREFIX_DEFAULT_KEY        = "default."
 	DEFAULT_SERVICE_FILTERS   = "echo"
 	DEFAULT_REFERENCE_FILTERS = ""
+	GENERIC_REFERENCE_FILTERS = "generic"
+	GENERIC                   = "$invoke"
 	ECHO                      = "$echo"
 )
 
diff --git a/config/reference_config.go b/config/reference_config.go
index 0ab24e184..c1565004c 100644
--- a/config/reference_config.go
+++ b/config/reference_config.go
@@ -170,7 +170,7 @@ func (refconfig *ReferenceConfig) getUrlMap() url.Values {
 
 	//filter
 	urlMap.Set(constant.REFERENCE_FILTER_KEY, mergeValue(consumerConfig.Filter, refconfig.Filter, constant.DEFAULT_REFERENCE_FILTERS))
-
+	urlMap.Set(constant.REFERENCE_FILTER_KEY, mergeValue(consumerConfig.Filter, refconfig.Filter, constant.GENERIC_REFERENCE_FILTERS))
 	for _, v := range refconfig.Methods {
 		urlMap.Set("methods."+v.Name+"."+constant.LOADBALANCE_KEY, v.Loadbalance)
 		urlMap.Set("methods."+v.Name+"."+constant.RETRIES_KEY, strconv.FormatInt(v.Retries, 10))
diff --git a/filter/impl/generic_filter.go b/filter/impl/generic_filter.go
new file mode 100644
index 000000000..14da6eeab
--- /dev/null
+++ b/filter/impl/generic_filter.go
@@ -0,0 +1,75 @@
+package impl
+
+import (
+	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/common/extension"
+	"github.com/apache/dubbo-go/filter"
+	"github.com/apache/dubbo-go/protocol"
+	invocation2 "github.com/apache/dubbo-go/protocol/invocation"
+	"reflect"
+	"strings"
+)
+
+const (
+	GENERIC = "generic"
+)
+
+func init() {
+	extension.SetFilter(GENERIC, GetGenericFilter)
+}
+
+//  when do a generic invoke, struct need to be map
+
+type GenericFilter struct{}
+
+func (ef *GenericFilter) Invoke(invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
+	if invocation.MethodName() == constant.GENERIC {
+		var newArguments = invocation.Arguments()
+		for i := range newArguments {
+			newArguments[i] = Struct2MapAll(newArguments[i])
+		}
+		newInvocation := invocation2.NewRPCInvocation(invocation.MethodName(), newArguments, invocation.Attachments())
+		return invoker.Invoke(newInvocation)
+	}
+	return invoker.Invoke(invocation)
+
+}
+
+func (ef *GenericFilter) OnResponse(result protocol.Result, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
+	return result
+}
+
+func GetGenericFilter() filter.Filter {
+	return &GenericFilter{}
+}
+func Struct2MapAll(obj interface{}) map[string]interface{} {
+	t := reflect.TypeOf(obj)
+	v := reflect.ValueOf(obj)
+	result := make(map[string]interface{})
+	if reflect.TypeOf(obj).Kind() == reflect.Struct {
+		for i := 0; i < t.NumField(); i++ {
+			if v.Field(i).Kind() == reflect.Struct {
+				if v.Field(i).CanInterface() {
+					result[headerAtoa(t.Field(i).Name)] = Struct2MapAll(v.Field(i).Interface())
+				} else {
+					println("not in to map,field:" + t.Field(i).Name)
+				}
+			} else {
+				if v.Field(i).CanInterface() {
+					if tagName := t.Field(i).Tag.Get("m"); tagName == "" {
+						result[headerAtoa(t.Field(i).Name)] = v.Field(i).Interface()
+					} else {
+						result[tagName] = v.Field(i).Interface()
+					}
+				} else {
+					println("not in to map,field:" + t.Field(i).Name)
+				}
+			}
+		}
+	}
+	return result
+}
+func headerAtoa(a string) (b string) {
+	b = strings.ToLower(a[:1]) + a[1:]
+	return
+}
-- 
GitLab