@@ -42,6 +42,7 @@ import (
4242import (
4343 "dubbo.apache.org/dubbo-go/v3/common"
4444 "dubbo.apache.org/dubbo-go/v3/common/constant"
45+ "dubbo.apache.org/dubbo-go/v3/common/dubboutil"
4546 "dubbo.apache.org/dubbo-go/v3/global"
4647 "dubbo.apache.org/dubbo-go/v3/internal"
4748 "dubbo.apache.org/dubbo-go/v3/protocol/base"
@@ -320,109 +321,133 @@ func (s *Server) compatRegisterHandler(interfaceName string, svc dubbo3.Dubbo3Gr
320321 }
321322}
322323
323- // handleServiceWithInfo injects invoker and create handler based on ServiceInfo
324+ // handleServiceWithInfo injects invoker and creates handlers based on ServiceInfo.
325+ // Each method is registered under both its original procedure path and the
326+ // first-rune-swapped path, so Java clients (camelCase) and Go clients
327+ // (PascalCase) can both reach the same handler without polluting ServiceInfo.
324328func (s * Server ) handleServiceWithInfo (interfaceName string , invoker base.Invoker , info * common.ServiceInfo , opts ... tri.HandlerOption ) {
325329 for _ , method := range info .Methods {
326330 m := method
327331 procedure := joinProcedure (interfaceName , method .Name )
328- switch m .Type {
329- case constant .CallUnary :
330- _ = s .triServer .RegisterUnaryHandler (
331- procedure ,
332- m .ReqInitFunc ,
333- func (ctx context.Context , req * tri.Request ) (* tri.Response , error ) {
334- var args []any
335- if argsRaw , ok := req .Msg .([]any ); ok {
336- // non-idl mode, req.Msg consists of many arguments
337- for _ , argRaw := range argsRaw {
338- // refer to createServiceInfoWithReflection, in ReqInitFunc, argRaw is a pointer to real arg.
339- // so we have to invoke Elem to get the real arg.
340- args = append (args , reflect .ValueOf (argRaw ).Elem ().Interface ())
341- }
342- } else {
343- // triple idl mode and old triple idl mode
344- args = append (args , req .Msg )
345- }
346- attachments := generateAttachments (req .Header ())
347- // inject attachments
348- ctx = context .WithValue (ctx , constant .AttachmentKey , attachments )
349- invo := invocation .NewRPCInvocation (m .Name , args , attachments )
350- res := invoker .Invoke (ctx , invo )
351- // todo(DMwangnima): modify InfoInvoker to get a unified processing logic
352- // please refer to server/InfoInvoker.Invoke()
353- var triResp * tri.Response
354- if existingResp , ok := res .Result ().(* tri.Response ); ok {
355- triResp = existingResp
356- } else {
357- // please refer to proxy/proxy_factory/ProxyInvoker.Invoke
358- triResp = tri .NewResponse ([]any {res .Result ()})
332+ s .registerMethodHandler (procedure , m , invoker , opts ... )
333+
334+ // Also register the first-rune-swapped procedure so that Java clients
335+ // sending camelCase method names (e.g. getUser) reach Go handlers
336+ // registered as PascalCase (e.g. GetUser), and vice-versa.
337+ //
338+ // The original m (with the Go/proto name) is passed unchanged so that:
339+ // 1. infoProxyInvoker can look up the method by its canonical name.
340+ // 2. Method-scoped provider config ("methods.SayHello.*") continues
341+ // to apply; filters look up via invocation.MethodName(), which
342+ // must match the key written by server/action.go.
343+ //
344+ // Only the HTTP procedure path varies between the two registrations;
345+ // the invocation name and MethodInfo are shared.
346+ if swappedName := dubboutil .SwapCaseFirstRune (method .Name ); joinProcedure (interfaceName , swappedName ) != procedure {
347+ s .registerMethodHandler (joinProcedure (interfaceName , swappedName ), m , invoker , opts ... )
348+ }
349+ }
350+ }
351+
352+ // registerMethodHandler registers a single method handler for the given procedure path.
353+ func (s * Server ) registerMethodHandler (procedure string , m common.MethodInfo , invoker base.Invoker , opts ... tri.HandlerOption ) {
354+ switch m .Type {
355+ case constant .CallUnary :
356+ _ = s .triServer .RegisterUnaryHandler (
357+ procedure ,
358+ m .ReqInitFunc ,
359+ func (ctx context.Context , req * tri.Request ) (* tri.Response , error ) {
360+ var args []any
361+ if argsRaw , ok := req .Msg .([]any ); ok {
362+ // non-idl mode, req.Msg consists of many arguments
363+ for _ , argRaw := range argsRaw {
364+ // refer to createServiceInfoWithReflection, in ReqInitFunc, argRaw is a pointer to real arg.
365+ // so we have to invoke Elem to get the real arg.
366+ args = append (args , reflect .ValueOf (argRaw ).Elem ().Interface ())
359367 }
360- for k , v := range res .Attachments () {
361- switch val := v .(type ) {
362- case string :
363- tri .AppendToOutgoingContext (ctx , k , val )
364- case []string :
365- for _ , v := range val {
366- tri .AppendToOutgoingContext (ctx , k , v )
367- }
368+ } else {
369+ // triple idl mode and old triple idl mode
370+ args = append (args , req .Msg )
371+ }
372+ attachments := generateAttachments (req .Header ())
373+ // inject attachments
374+ ctx = context .WithValue (ctx , constant .AttachmentKey , attachments )
375+ invo := invocation .NewRPCInvocation (m .Name , args , attachments )
376+ res := invoker .Invoke (ctx , invo )
377+ // todo(DMwangnima): modify InfoInvoker to get a unified processing logic
378+ // please refer to server/InfoInvoker.Invoke()
379+ var triResp * tri.Response
380+ if existingResp , ok := res .Result ().(* tri.Response ); ok {
381+ triResp = existingResp
382+ } else {
383+ // please refer to proxy/proxy_factory/ProxyInvoker.Invoke
384+ triResp = tri .NewResponse ([]any {res .Result ()})
385+ }
386+ for k , v := range res .Attachments () {
387+ switch val := v .(type ) {
388+ case string :
389+ tri .AppendToOutgoingContext (ctx , k , val )
390+ case []string :
391+ for _ , v := range val {
392+ tri .AppendToOutgoingContext (ctx , k , v )
368393 }
369394 }
395+ }
396+ return triResp , res .Error ()
397+ },
398+ opts ... ,
399+ )
400+ case constant .CallClientStream :
401+ _ = s .triServer .RegisterClientStreamHandler (
402+ procedure ,
403+ func (ctx context.Context , stream * tri.ClientStream ) (* tri.Response , error ) {
404+ var args []any
405+ args = append (args , m .StreamInitFunc (stream ))
406+ attachments := generateAttachments (stream .RequestHeader ())
407+ // inject attachments
408+ ctx = context .WithValue (ctx , constant .AttachmentKey , attachments )
409+ invo := invocation .NewRPCInvocation (m .Name , args , attachments )
410+ res := invoker .Invoke (ctx , invo )
411+ if triResp , ok := res .Result ().(* tri.Response ); ok {
370412 return triResp , res .Error ()
371- },
372- opts ... ,
373- )
374- case constant .CallClientStream :
375- _ = s .triServer .RegisterClientStreamHandler (
376- procedure ,
377- func (ctx context.Context , stream * tri.ClientStream ) (* tri.Response , error ) {
378- var args []any
379- args = append (args , m .StreamInitFunc (stream ))
380- attachments := generateAttachments (stream .RequestHeader ())
381- // inject attachments
382- ctx = context .WithValue (ctx , constant .AttachmentKey , attachments )
383- invo := invocation .NewRPCInvocation (m .Name , args , attachments )
384- res := invoker .Invoke (ctx , invo )
385- if triResp , ok := res .Result ().(* tri.Response ); ok {
386- return triResp , res .Error ()
387- }
388- // please refer to proxy/proxy_factory/ProxyInvoker.Invoke
389- triResp := tri .NewResponse ([]any {res .Result ()})
390- return triResp , res .Error ()
391- },
392- opts ... ,
393- )
394- case constant .CallServerStream :
395- _ = s .triServer .RegisterServerStreamHandler (
396- procedure ,
397- m .ReqInitFunc ,
398- func (ctx context.Context , req * tri.Request , stream * tri.ServerStream ) error {
399- var args []any
400- args = append (args , req .Msg , m .StreamInitFunc (stream ))
401- attachments := generateAttachments (req .Header ())
402- // inject attachments
403- ctx = context .WithValue (ctx , constant .AttachmentKey , attachments )
404- invo := invocation .NewRPCInvocation (m .Name , args , attachments )
405- res := invoker .Invoke (ctx , invo )
406- return res .Error ()
407- },
408- opts ... ,
409- )
410- case constant .CallBidiStream :
411- _ = s .triServer .RegisterBidiStreamHandler (
412- procedure ,
413- func (ctx context.Context , stream * tri.BidiStream ) error {
414- var args []any
415- args = append (args , m .StreamInitFunc (stream ))
416- attachments := generateAttachments (stream .RequestHeader ())
417- // inject attachments
418- ctx = context .WithValue (ctx , constant .AttachmentKey , attachments )
419- invo := invocation .NewRPCInvocation (m .Name , args , attachments )
420- res := invoker .Invoke (ctx , invo )
421- return res .Error ()
422- },
423- opts ... ,
424- )
425- }
413+ }
414+ // please refer to proxy/proxy_factory/ProxyInvoker.Invoke
415+ triResp := tri .NewResponse ([]any {res .Result ()})
416+ return triResp , res .Error ()
417+ },
418+ opts ... ,
419+ )
420+ case constant .CallServerStream :
421+ _ = s .triServer .RegisterServerStreamHandler (
422+ procedure ,
423+ m .ReqInitFunc ,
424+ func (ctx context.Context , req * tri.Request , stream * tri.ServerStream ) error {
425+ var args []any
426+ args = append (args , req .Msg , m .StreamInitFunc (stream ))
427+ attachments := generateAttachments (req .Header ())
428+ // inject attachments
429+ ctx = context .WithValue (ctx , constant .AttachmentKey , attachments )
430+ invo := invocation .NewRPCInvocation (m .Name , args , attachments )
431+ res := invoker .Invoke (ctx , invo )
432+ return res .Error ()
433+ },
434+ opts ... ,
435+ )
436+ case constant .CallBidiStream :
437+ _ = s .triServer .RegisterBidiStreamHandler (
438+ procedure ,
439+ func (ctx context.Context , stream * tri.BidiStream ) error {
440+ var args []any
441+ args = append (args , m .StreamInitFunc (stream ))
442+ attachments := generateAttachments (stream .RequestHeader ())
443+ // inject attachments
444+ ctx = context .WithValue (ctx , constant .AttachmentKey , attachments )
445+ invo := invocation .NewRPCInvocation (m .Name , args , attachments )
446+ res := invoker .Invoke (ctx , invo )
447+ return res .Error ()
448+ },
449+ opts ... ,
450+ )
426451 }
427452}
428453
0 commit comments