Tsukikage7 opened a new pull request, #3154:
URL: https://github.com/apache/dubbo-go/pull/3154

   ## What this PR does
   
   This PR implements **Triple protocol generic call** support for dubbo-go, 
enabling Go clients to invoke Java Dubbo services without pre-generated stubs 
and vice versa.
   
   ### Background
   
   Generic call (泛化调用) is a core feature in Dubbo ecosystem that allows service 
invocation without IDL/interface definitions. While dubbo-go already supports 
generic call for the Dubbo protocol, Triple protocol generic call was missing, 
making it impossible for Go and Java services to interoperate via Triple 
protocol in non-IDL mode.
   
   ### Design Overview
   
   The key challenge is that Java Dubbo Triple protocol uses a specific wire 
format for non-IDL mode:
   
   ```
   ┌─────────────────────────────────────────────────────────────┐
   │                    Wire Format                              │
   ├─────────────────────────────────────────────────────────────┤
   │  Content-Type: application/proto                            │
   │                                                             │
   │  Request:  TripleRequestWrapper (protobuf)                  │
   │            ├── serializeType: "hessian2"                    │
   │            ├── args: [hessian2(arg1), hessian2(arg2), ...]  │
   │            └── argTypes: ["java.lang.String", ...]          │
   │                                                             │
   │  Response: TripleResponseWrapper (protobuf)                 │
   │            ├── serializeType: "hessian2"                    │
   │            ├── data: hessian2(result)                       │
   │            └── type: "org.apache.dubbo.samples.User"        │
   └─────────────────────────────────────────────────────────────┘
   ```
   
   This is a **two-layer serialization**: protobuf wrapper on the outside, 
hessian2 data on the inside.
   
   ### Implementation Details
   
   #### 1. New `WrapperCodec` Interface (`codec.go`)
   
   ```go
   type WrapperCodec interface {
       Codec
       WireCodecName() string  // Returns "proto" for Content-Type
   }
   ```
   
   This interface allows a codec to use different names for:
   - Internal registration: `Name()` returns "hessian2"
   - Wire format: `WireCodecName()` returns "proto"
   
   #### 2. New `protoWrapperCodec` (`codec.go`)
   
   Client-side codec that:
   - Wraps request arguments in `TripleRequestWrapper`
   - Unwraps response from `TripleResponseWrapper`
   - Uses hessian2 for inner data serialization
   
   ```go
   type protoWrapperCodec struct {
       innerCodec Codec  // hessian2Codec
   }
   
   func (c *protoWrapperCodec) Marshal(message any) ([]byte, error) {
       // 1. Serialize each arg with hessian2
       // 2. Get Java type for each arg
       // 3. Wrap in TripleRequestWrapper
       // 4. Marshal with protobuf
   }
   ```
   
   #### 3. Enhanced `protoBinaryCodec` (`codec.go`)
   
   Server-side enhancement to handle incoming wrapped requests:
   - Detects non-proto.Message types
   - Unwraps from `TripleRequestWrapper`/`TripleResponseWrapper`
   - Deserializes with hessian2
   
   #### 4. Generic Filter Enhancement (`filter/generic/filter.go`)
   
   Added `parameterRawValues` support for Triple protocol:
   
   ```go
   // For Triple protocol, we need [methodName, types, args, reply]
   // Triple invoker slices as: request = inRaw[0:len-1], reply = inRaw[len-1]
   parameterRawValues := []any{mtdName, types, args, reply}
   ```
   
   #### 5. Server-side Generic Call Handler (`server/server.go`)
   
   Auto-registers `$invoke` method for services:
   
   ```go
   func registerGenericInvokeMethod(srv any, interfaceName string) 
map[string]MethodInfo {
       return map[string]MethodInfo{
           constant.Generic: {  // "$invoke"
               Name:           constant.Generic,
               StreamType:     StreamTypeUnary,
               MethodFunc:     genericInvokeHandler(srv),
               ReqInitFunc:    func() any { return []any{new(string), 
new([]string), new([]any)} },
           },
       }
   }
   ```
   
   ### Call Flow
   
   ```
   Go Client                                           Java Server
       │                                                    │
       │  conn.CallUnary(ctx, args, &result, "GetUser")    │
       │         │                                          │
       │         ▼                                          │
       │  Generic Filter: $invoke("GetUser", types, args)  │
       │         │                                          │
       │         ▼                                          │
       │  protoWrapperCodec.Marshal()                       │
       │    ├── hessian2 serialize args                     │
       │    └── protobuf wrap in TripleRequestWrapper       │
       │         │                                          │
       │         ▼                                          │
       │  ════════════════════════════════════════════════► │
       │   HTTP/2 + Content-Type: application/proto         │
       │                                                    │
       │  ◄════════════════════════════════════════════════ │
       │   TripleResponseWrapper (protobuf)                 │
       │         │                                          │
       │         ▼                                          │
       │  protoWrapperCodec.Unmarshal()                     │
       │    ├── protobuf unwrap TripleResponseWrapper       │
       │    └── hessian2 deserialize → User object          │
       │                                                    │
   ```
   
   ### Files Changed
   
   | File | Changes |
   |------|---------|
   | `protocol/triple/triple_protocol/codec.go` | Add `WrapperCodec` interface, 
`protoWrapperCodec`, enhance `protoBinaryCodec` |
   | `protocol/triple/triple_protocol/codec_wrapper_test.go` | Comprehensive 
unit tests (631 lines) |
   | `filter/generic/filter.go` | Add `parameterRawValues` for Triple protocol |
   | `client/options.go` | Add `WithGeneric()` option |
   | `server/server.go` | Add generic call handler registration |
   | `protocol/triple/client.go` | Wire up wrapper codec for generic mode |
   | `protocol/triple/server.go` | Handle generic call on server side |
   | `protocol/triple/triple.go` | Minor adjustments for generic support |
   | `common/constant/key.go` | Add generic-related constants |
   | `protocol/triple/triple_protocol/protocol_grpc.go` | Use 
`getWireCodecName()` for Content-Type |
   | `protocol/triple/triple_protocol/protocol_triple.go` | Use 
`getWireCodecName()` for Content-Type |
   
   ### Testing
   
   **Unit Tests**: 631 lines of comprehensive tests covering:
   - `protoWrapperCodec` marshal/unmarshal
   - `protoBinaryCodec` wrapper handling
   - Various data types (string, int, POJO, arrays, maps)
   - Edge cases and error scenarios
   
   **Integration Tests**:
   | Scenario | Result |
   |----------|--------|
   | Go client → Java server (Dubbo protocol) | PASS |
   | Go client → Java server (Triple protocol) | PASS |
   | Java client → Go server (Triple protocol) | PASS |
   | Go client → Go server (Triple protocol) | PASS |
   
   ### Usage Example
   
   ```go
   // Create client with Triple protocol
   cli, _ := ins.NewClient(
       client.WithClientProtocolTriple(),
       client.WithClientSerialization(constant.Hessian2Serialization),
   )
   
   // Dial with generic mode enabled
   conn, _ := cli.Dial(
       "org.apache.dubbo.samples.UserProvider",
       client.WithURL("tri://127.0.0.1:50052"),
       client.WithGeneric(),  // Enable generic call
   )
   
   // Make generic call without pre-generated stubs
   var result interface{}
   err := conn.CallUnary(ctx, []interface{}{"user123"}, &result, "GetUser")
   ```
   
   ### Compatibility
   
   - **Backward Compatible**: Existing IDL-based Triple calls are not affected
   - **Cross-Language**: Fully compatible with Java Dubbo 3.x Triple protocol
   - **Dubbo Protocol**: Existing Dubbo protocol generic call still works as 
before
   
   ---
   
   Signed-off-by: TsukiKage <[email protected]>
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to