| name | Dubbo Java interop from Go |
| description | Guides interoperability between dubbo-go v3 and dubbo-java — cross-language RPC calls using Triple+Protobuf or Dubbo+Hessian2. Use when user asks how to call a Java Dubbo service from Go, expose a Go service to Java clients, share a proto/interface across languages, or pick between Triple and Dubbo protocols for interop. |
Dubbo Java ↔ Go Interop
Interop is one of dubbo-go's distinctive strengths: a single service definition can be served by Go and consumed by Java (or vice versa) without a gateway. Two viable paths:
| Path | Wire format | Serialization | When to use |
|---|
| Triple + Protobuf (recommended) | HTTP/2 | Protobuf | New services, polyglot teams, gRPC-compatible clients |
| Dubbo + Hessian2 | TCP (dubbo) | Hessian2 | Calling existing Java services that were originally defined with Java interfaces (no .proto) |
Pick Triple unless you're integrating with an existing Hessian2-based Java codebase.
Path 1: Triple + Protobuf (recommended)
Shared .proto file drives both sides. Set both go_package and java_package:
syntax = "proto3";
package org.apache.dubbo.sample;
option go_package = "github.com/yourorg/yourapp/proto;greet";
option java_package = "org.apache.dubbo.sample";
option java_multiple_files = true;
service Greeter {
rpc SayHello(HelloRequest) returns (HelloReply);
}
message HelloRequest { string name = 1; }
message HelloReply { string message = 1; }
Go server — nothing interop-specific, just plain Triple:
srv, _ := server.NewServer(
server.WithServerProtocol(
protocol.WithPort(20000),
protocol.WithTriple(),
),
)
greet.RegisterGreeterHandler(srv, &impl{})
srv.Serve()
Testing interop without a client — Triple supports JSON over HTTP/1.1, so you can verify a Go Triple server from any HTTP tool:
curl -H "Content-Type: application/json" \
-d '{"name":"Dubbo"}' \
http://localhost:20000/org.apache.dubbo.sample.Greeter/sayHello
The path is /<java_package>.<service>/<method> — note the lowercase-first-letter method name (Java camelCase convention).
Java client calling the Go server uses standard dubbo-java APIs; no Go-specific code. See java_interop/protobuf-triple for the full working pair.
Rules of thumb for Triple interop
- Method name casing: Protobuf generators emit
SayHello in Go and sayHello on the Java wire. The HTTP route uses the lowercase-first form.
- Package must match: The
java_package in the proto is what Java's dubbo picks up as the interface FQN. Pick it deliberately — renaming later is a breaking change.
- Built-in reflection: Triple exposes gRPC reflection automatically, so Java clients using tools like
grpcurl can list services without extra config.
Path 2: Dubbo protocol + Hessian2 (Java-defined services)
Use this when the service was defined by a Java interface (no .proto) and you need to add a Go side.
The Go side must mirror the Java POJO exactly, via Hessian2 registration. Each field name, type, and JavaClassName() must match the Java class.
package greet
import (
dubbo_go_hessian2 "github.com/apache/dubbo-go-hessian2"
)
type GreetRequest struct {
Name string
}
func (x *GreetRequest) JavaClassName() string {
return "org.apache.dubbo.hessian2.api.GreetRequest"
}
type GreetResponse struct {
Greeting string
}
func (x *GreetResponse) JavaClassName() string {
return "org.apache.dubbo.hessian2.api.GreetResponse"
}
func init() {
dubbo_go_hessian2.RegisterPOJO(new(GreetRequest))
dubbo_go_hessian2.RegisterPOJO(new(GreetResponse))
}
Go server:
srv, _ := server.NewServer(
server.WithServerProtocol(
protocol.WithPort(20000),
protocol.WithDubbo(),
),
)
greet.RegisterGreetingsServiceHandler(srv, &impl{})
srv.Serve()
Generate the Go stub from the same proto that describes the Java interface with protoc-gen-go-dubbo (different plugin from protoc-gen-go-triple). That's what produces greet.dubbo.go and greet.hessian2.go.
See java_interop/non-protobuf-dubbo.
Hessian2 gotchas
- Field names are case-sensitive on the wire — Go's uppercase exports are serialized lowercase-first to match Java conventions. The hessian2 library handles this automatically, but custom struct tags can break it.
- Unsupported types: Go generics, channels, functions won't serialize. Stick to primitives, slices, maps, and other registered POJOs.
- Unregistered POJOs →
hessian: failed to decode at runtime. Always RegisterPOJO in the package's init().
- Java
enum maps to Go int (ordinal), not string — unless the Java side customized serialization.
- Time: Java
Date ↔ Go time.Time generally works; java.time.* types need extra care.
Service discovery across languages
If both sides use the same registry (Nacos / ZooKeeper), they discover each other automatically — the registry entry is language-agnostic, just a URL with protocol + address.
dubbo.NewInstance(
dubbo.WithName("polyglot-service"),
dubbo.WithRegistry(registry.WithNacos(), registry.WithAddress("127.0.0.1:8848")),
dubbo.WithProtocol(protocol.WithTriple(), protocol.WithPort(20000)),
)
See java_interop/service_discovery.
Decision table
| Scenario | Path |
|---|
| New service, Go + Java teams both need clients | Triple + Protobuf |
| Calling an existing Java Dubbo service defined by Java interface | Dubbo + Hessian2 |
| Legacy Java service exports both Triple and Dubbo endpoints | Triple + Protobuf on Go side |
| Need gRPC-compatible wire | Triple + Protobuf |
| Can't touch Java side, and it's not Protobuf | Dubbo + Hessian2 |
Reference samples
Official guide: Interoperability with Dubbo Java