1717import io .jooby .*;
1818import io .jooby .internal .grpc .DefaultGrpcProcessor ;
1919
20+ /**
21+ * Native gRPC extension for Jooby. *
22+ *
23+ * <p>This module allows you to run strictly-typed gRPC services alongside standard Jooby HTTP
24+ * routes on the exact same port. It completely bypasses standard HTTP/1.1 pipelines in favor of a
25+ * highly optimized, reactive, native interceptor tailored for HTTP/2 multiplexing and trailing
26+ * headers. *
27+ *
28+ * <h3>Usage</h3>
29+ *
30+ * <p>gRPC requires HTTP/2. Ensure your Jooby application is configured to use a supported server
31+ * (Undertow, Netty, or Jetty) with HTTP/2 enabled. *
32+ *
33+ * <pre>{@code
34+ * import io.jooby.Jooby;
35+ * import io.jooby.ServerOptions;
36+ * import io.jooby.grpc.GrpcModule;
37+ * * public class App extends Jooby {
38+ * {
39+ * setServerOptions(new ServerOptions().setHttp2(true).setSecurePort(8443));
40+ * * // Install the extension and register your services
41+ * install(new GrpcModule(new GreeterService()));
42+ * }
43+ * }
44+ * }</pre>
45+ *
46+ * *
47+ *
48+ * <h3>Dependency Injection</h3>
49+ *
50+ * <p>If your gRPC services require external dependencies (like repositories or configuration), you
51+ * can register the service classes instead of instances. The module will automatically provision
52+ * them using Jooby's DI registry (e.g., Guice, Spring) during the application startup phase. *
53+ *
54+ * <pre>{@code
55+ * public class App extends Jooby {
56+ * {
57+ * install(new GuiceModule());
58+ * * // Pass the class reference. Guice will instantiate it!
59+ * install(new GrpcModule(GreeterService.class));
60+ * }
61+ * }
62+ * }</pre>
63+ *
64+ * *
65+ *
66+ * <p><strong>Note:</strong> gRPC services are inherently registered as Singletons. Ensure your
67+ * service implementations are thread-safe and do not hold request-scoped state in instance
68+ * variables. *
69+ *
70+ * <h3>Logging</h3>
71+ *
72+ * <p>gRPC internally uses {@code java.util.logging}. This module automatically installs the {@link
73+ * SLF4JBridgeHandler} to redirect all internal gRPC logs to your configured SLF4J backend.
74+ */
2075public class GrpcModule implements Extension {
2176 private final List <BindableService > services = new ArrayList <>();
2277 private final List <Class <? extends BindableService >> serviceClasses = new ArrayList <>();
@@ -28,21 +83,45 @@ public class GrpcModule implements Extension {
2883 SLF4JBridgeHandler .install ();
2984 }
3085
86+ /**
87+ * Creates a new gRPC module with pre-instantiated service objects. * @param services One or more
88+ * fully instantiated gRPC services.
89+ */
3190 public GrpcModule (BindableService ... services ) {
3291 this .services .addAll (Arrays .asList (services ));
3392 }
3493
94+ /**
95+ * Creates a new gRPC module with service classes to be provisioned via Dependency Injection.
96+ * * @param serviceClasses One or more gRPC service classes to be resolved from the Jooby
97+ * registry.
98+ */
3599 @ SafeVarargs
36100 public GrpcModule (Class <? extends BindableService >... serviceClasses ) {
37101 bind (serviceClasses );
38102 }
39103
104+ /**
105+ * Registers additional gRPC service classes to be provisioned via Dependency Injection. * @param
106+ * serviceClasses One or more gRPC service classes to be resolved from the Jooby registry.
107+ *
108+ * @return This module for chaining.
109+ */
40110 @ SafeVarargs
41111 public final GrpcModule bind (Class <? extends BindableService >... serviceClasses ) {
42112 this .serviceClasses .addAll (List .of (serviceClasses ));
43113 return this ;
44114 }
45115
116+ /**
117+ * Installs the gRPC extension into the Jooby application. *
118+ *
119+ * <p>This method sets up the {@link GrpcProcessor} SPI, registers native fallback routes, and
120+ * defers DI resolution and the starting of the embedded in-process gRPC server to the {@code
121+ * onStarting} lifecycle hook. * @param app The target Jooby application.
122+ *
123+ * @throws Exception If an error occurs during installation.
124+ */
46125 @ Override
47126 public void install (@ NonNull Jooby app ) throws Exception {
48127 var serverName = app .getName ();
@@ -78,6 +157,14 @@ public void install(@NonNull Jooby app) throws Exception {
78157 });
79158 }
80159
160+ /**
161+ * Internal helper to register a service with the gRPC builder, extract its method descriptors,
162+ * and map a fail-fast route in the Jooby router. * @param app The target Jooby application.
163+ *
164+ * @param server The in-process server builder.
165+ * @param registry The method descriptor registry.
166+ * @param service The provisioned gRPC service to bind.
167+ */
81168 private static void bindService (
82169 Jooby app ,
83170 InProcessServerBuilder server ,
@@ -89,7 +176,9 @@ private static void bindService(
89176 String methodFullName = descriptor .getFullMethodName ();
90177 registry .put (methodFullName , descriptor );
91178 String routePath = "/" + methodFullName ;
92- //
179+
180+ // Map a fallback route. If a request hits this, it means the native SPI interceptor
181+ // failed to upgrade the request, typically due to a missing HTTP/2 configuration.
93182 app .post (
94183 routePath ,
95184 ctx -> {
0 commit comments