title: gRPC Support sidebar_position: 17 id: grpc_support license: | Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Fory can generate Java gRPC service companions for schemas that define services. The generated service code uses normal grpc-java channels, servers, deadlines, status codes, interceptors, and transport security, while request and response objects are serialized with Fory instead of protobuf.
Use this mode when both sides of the RPC are generated from the same Fory IDL, protobuf IDL, or FlatBuffers IDL and you want gRPC transport semantics with Fory payload encoding. Use standard protobuf gRPC code generation when your API must be consumed by generic protobuf clients, reflection tools, or components that expect protobuf message bytes.
For Scala generated grpc-java companions, see Scala gRPC Support. For Kotlin coroutine stubs and service bases, see Kotlin gRPC Support.
The generated Java service files compile against grpc-java. Fory Java artifacts do not add gRPC as a hard dependency, so add grpc-java dependencies in your application build and align the version with the rest of your service stack.
Maven:
<dependencies> <dependency> <groupId>org.apache.fory</groupId> <artifactId>fory-core</artifactId> <version>${fory.version}</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-api</artifactId> <version>${grpc.version}</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-stub</artifactId> <version>${grpc.version}</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-netty-shaded</artifactId> <version>${grpc.version}</version> </dependency> </dependencies>
Gradle:
dependencies { implementation("org.apache.fory:fory-core:$foryVersion") implementation("io.grpc:grpc-api:$grpcVersion") implementation("io.grpc:grpc-stub:$grpcVersion") implementation("io.grpc:grpc-netty-shaded:$grpcVersion") }
Service definitions can come from Fory IDL, protobuf IDL, or FlatBuffers rpc_service definitions. A Fory IDL service looks like this:
package demo.greeter; message HelloRequest { string name = 1; } message HelloReply { string reply = 1; } service Greeter { rpc SayHello (HelloRequest) returns (HelloReply); }
Generate Java model and gRPC companion code with --grpc:
foryc service.fdl --java_out=./generated/java --grpc
For this schema, the Java generator emits:
| File | Purpose |
|---|---|
HelloRequest.java | Fory model type for the request |
HelloReply.java | Fory model type for the response |
GreeterForyModule.java | Fory registration module for generated types |
GreeterGrpc.java | grpc-java service base class, stubs, codecs |
Extend the generated GreeterGrpc.GreeterImplBase class and register it with a standard grpc-java Server.
package demo.greeter; import io.grpc.Server; import io.grpc.ServerBuilder; import io.grpc.stub.StreamObserver; final class GreeterService extends GreeterGrpc.GreeterImplBase { @Override public void sayHello( HelloRequest request, StreamObserver<HelloReply> responseObserver) { HelloReply reply = new HelloReply(); reply.setReply("Hello, " + request.getName()); responseObserver.onNext(reply); responseObserver.onCompleted(); } } public final class GreeterServer { public static void main(String[] args) throws Exception { Server server = ServerBuilder.forPort(50051) .addService(new GreeterService()) .build() .start(); server.awaitTermination(); } }
Generated request and response types are registered by the generated code, so service implementations do not perform manual serializer registration.
Use the generated stubs with an ordinary grpc-java channel:
package demo.greeter; import io.grpc.ManagedChannel; import io.grpc.ManagedChannelBuilder; public final class GreeterClient { public static void main(String[] args) { ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 50051) .usePlaintext() .build(); try { GreeterGrpc.GreeterBlockingStub stub = GreeterGrpc.newBlockingStub(channel); HelloRequest request = new HelloRequest(); request.setName("Fory"); HelloReply reply = stub.sayHello(request); System.out.println(reply.getReply()); } finally { channel.shutdownNow(); } } }
For asynchronous calls, use GreeterGrpc.newStub(channel). For future-based unary calls, use GreeterGrpc.newFutureStub(channel).
Fory service definitions can use the same gRPC streaming shapes:
service Greeter { rpc SayHello (HelloRequest) returns (HelloReply); rpc LotsOfReplies (HelloRequest) returns (stream HelloReply); rpc LotsOfGreetings (stream HelloRequest) returns (HelloReply); rpc Chat (stream HelloRequest) returns (stream HelloReply); }
Generated Java service methods follow grpc-java conventions:
| IDL shape | Server method shape | Client method shape |
|---|---|---|
rpc A (Req) returns (Res) | void a(Req request, StreamObserver<Res> responses) | blocking, async, and future unary stub |
rpc A (Req) returns (stream Res) | void a(Req request, StreamObserver<Res> responses) | blocking iterator or async observer |
rpc A (stream Req) returns (Res) | StreamObserver<Req> a(StreamObserver<Res> responses) | async request observer |
rpc A (stream Req) returns (stream Res) | StreamObserver<Req> a(StreamObserver<Res> responses) | async request observer |
Server implementations can use the generated streaming method shapes directly:
package demo.greeter; import io.grpc.stub.StreamObserver; import java.util.ArrayList; import java.util.List; final class GreeterService extends GreeterGrpc.GreeterImplBase { @Override public void lotsOfReplies( HelloRequest request, StreamObserver<HelloReply> responseObserver) { HelloReply first = new HelloReply(); first.setReply("Hello, " + request.getName()); responseObserver.onNext(first); HelloReply second = new HelloReply(); second.setReply("Welcome, " + request.getName()); responseObserver.onNext(second); responseObserver.onCompleted(); } @Override public StreamObserver<HelloRequest> lotsOfGreetings( StreamObserver<HelloReply> responseObserver) { List<String> names = new ArrayList<>(); return new StreamObserver<>() { @Override public void onNext(HelloRequest request) { names.add(request.getName()); } @Override public void onError(Throwable error) { responseObserver.onError(error); } @Override public void onCompleted() { HelloReply reply = new HelloReply(); reply.setReply(String.join(", ", names)); responseObserver.onNext(reply); responseObserver.onCompleted(); } }; } @Override public StreamObserver<HelloRequest> chat( StreamObserver<HelloReply> responseObserver) { return new StreamObserver<>() { @Override public void onNext(HelloRequest request) { HelloReply reply = new HelloReply(); reply.setReply("Hello, " + request.getName()); responseObserver.onNext(reply); } @Override public void onError(Throwable error) { responseObserver.onError(error); } @Override public void onCompleted() { responseObserver.onCompleted(); } }; } }
Generated clients return the standard grpc-java call shapes:
package demo.greeter; import io.grpc.stub.StreamObserver; import java.util.Iterator; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; final class StreamingClient { private final GreeterGrpc.GreeterBlockingStub blockingStub; private final GreeterGrpc.GreeterStub asyncStub; StreamingClient( GreeterGrpc.GreeterBlockingStub blockingStub, GreeterGrpc.GreeterStub asyncStub) { this.blockingStub = blockingStub; this.asyncStub = asyncStub; } void run() throws InterruptedException { Iterator<HelloReply> replies = blockingStub.lotsOfReplies(newRequest("Fory")); while (replies.hasNext()) { System.out.println(replies.next().getReply()); } CountDownLatch greetingsDone = new CountDownLatch(1); StreamObserver<HelloRequest> greetings = asyncStub.lotsOfGreetings(new StreamObserver<>() { @Override public void onNext(HelloReply reply) { System.out.println(reply.getReply()); } @Override public void onError(Throwable error) { greetingsDone.countDown(); } @Override public void onCompleted() { greetingsDone.countDown(); } }); greetings.onNext(newRequest("Ada")); greetings.onNext(newRequest("Grace")); greetings.onCompleted(); greetingsDone.await(5, TimeUnit.SECONDS); CountDownLatch chatDone = new CountDownLatch(1); StreamObserver<HelloRequest> chat = asyncStub.chat(new StreamObserver<>() { @Override public void onNext(HelloReply reply) { System.out.println(reply.getReply()); } @Override public void onError(Throwable error) { chatDone.countDown(); } @Override public void onCompleted() { chatDone.countDown(); } }); chat.onNext(newRequest("Fory")); chat.onCompleted(); chatDone.await(5, TimeUnit.SECONDS); } private static HelloRequest newRequest(String name) { HelloRequest request = new HelloRequest(); request.setName(name); return request; } }
The generated descriptors preserve the exact IDL service and method names for the gRPC path.
The generated service code only replaces request and response serialization. All normal gRPC operational features still belong to grpc-java:
io.grpc or Guava ClassesAdd the grpc-java dependencies shown above. Generated Fory service files import grpc-java APIs, but Fory Java artifacts intentionally do not depend on gRPC.
UNIMPLEMENTEDConfirm that the generated service implementation is registered with ServerBuilder.addService(...), and that the client and server were generated from the same package, service, and method names.
Fory gRPC companions do not use protobuf wire encoding for messages. Use a Fory-generated client for Fory-generated services, or provide a separate protobuf service endpoint for generic protobuf clients.