dubbo.apache.org/dubbo-go/v3@v3.1.1/filter/generic/filter.go (about) 1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 // Package generic provides generic invoke filter. 19 package generic 20 21 import ( 22 "context" 23 "sync" 24 ) 25 26 import ( 27 hessian "github.com/apache/dubbo-go-hessian2" 28 29 "github.com/dubbogo/gost/log/logger" 30 ) 31 32 import ( 33 "dubbo.apache.org/dubbo-go/v3/common/constant" 34 "dubbo.apache.org/dubbo-go/v3/common/extension" 35 "dubbo.apache.org/dubbo-go/v3/filter" 36 "dubbo.apache.org/dubbo-go/v3/protocol" 37 invocation2 "dubbo.apache.org/dubbo-go/v3/protocol/invocation" 38 ) 39 40 var ( 41 genericOnce sync.Once 42 instance *genericFilter 43 ) 44 45 func init() { 46 extension.SetFilter(constant.GenericFilterKey, newGenericFilter) 47 } 48 49 // genericFilter ensures the structs are converted to maps, this filter is for consumer 50 type genericFilter struct{} 51 52 func newGenericFilter() filter.Filter { 53 if instance == nil { 54 genericOnce.Do(func() { 55 instance = &genericFilter{} 56 }) 57 } 58 return instance 59 } 60 61 // Invoke turns the parameters to map for generic method 62 func (f *genericFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result { 63 if isCallingToGenericService(invoker, invocation) { 64 65 mtdname := invocation.MethodName() 66 oldargs := invocation.Arguments() 67 68 types := make([]string, 0, len(oldargs)) 69 args := make([]hessian.Object, 0, len(oldargs)) 70 71 // get generic info from attachments of invocation, the default value is "true" 72 generic := invocation.GetAttachmentWithDefaultValue(constant.GenericKey, constant.GenericSerializationDefault) 73 // get generalizer according to value in the `generic` 74 g := getGeneralizer(generic) 75 76 for _, arg := range oldargs { 77 // use the default generalizer(MapGeneralizer) 78 typ, err := g.GetType(arg) 79 if err != nil { 80 logger.Errorf("failed to get type, %v", err) 81 } 82 obj, err := g.Generalize(arg) 83 if err != nil { 84 logger.Errorf("generalization failed, %v", err) 85 return invoker.Invoke(ctx, invocation) 86 } 87 types = append(types, typ) 88 args = append(args, obj) 89 } 90 91 // construct a new invocation for generic call 92 newargs := []interface{}{ 93 mtdname, 94 types, 95 args, 96 } 97 newivc := invocation2.NewRPCInvocation(constant.Generic, newargs, invocation.Attachments()) 98 newivc.SetReply(invocation.Reply()) 99 newivc.Attachments()[constant.GenericKey] = invoker.GetURL().GetParam(constant.GenericKey, "") 100 101 return invoker.Invoke(ctx, newivc) 102 } else if isMakingAGenericCall(invoker, invocation) { 103 invocation.Attachments()[constant.GenericKey] = invoker.GetURL().GetParam(constant.GenericKey, "") 104 } 105 return invoker.Invoke(ctx, invocation) 106 } 107 108 // OnResponse dummy process, returns the result directly 109 func (f *genericFilter) OnResponse(_ context.Context, result protocol.Result, _ protocol.Invoker, 110 _ protocol.Invocation) protocol.Result { 111 return result 112 }