From d41c3b3e2ef7eb362feceb47f4ef33a3ac93e7b6 Mon Sep 17 00:00:00 2001 From: Edgar Espina Date: Mon, 6 Apr 2026 06:42:47 -0300 Subject: [PATCH 1/5] tRPC: remove from 'core' - remove tRPC from core, including: - annotation `@Trpc` now is on `io.jooby.annotation.trpc` - `jooby-trpc` is now `jooby-trpc-generator` - package `io.jooby.rpc.trpc` is now `io.jooby.trpc` - split `json` bridge into `jooby-trpc-jackson2`, `jooby-trpc-jackson-3`, `jooby-trpc-avaje-jsonb` - fix #3889 --- docs/asciidoc/tRPC.adoc | 49 +++--- jooby/src/main/java/module-info.java | 1 - modules/jooby-apt/pom.xml | 7 + .../java/io/jooby/apt/JoobyProcessor.java | 6 +- .../java/io/jooby/internal/apt/TrpcRoute.java | 50 +++--- .../io/jooby/internal/apt/TrpcRouter.java | 9 +- .../test/java/tests/i3863/MixedMutation.java | 1 + .../java/tests/i3863/MixedTrpcAnnotation.java | 1 + .../test/java/tests/i3863/OverloadTrpc.java | 2 +- .../tests/i3863/SpecificTrpcAnnotation.java | 2 +- .../TopLevelTrpcDoesNothingByItSelf.java | 2 +- .../jooby/avaje/jsonb/AvajeJsonbModule.java | 11 -- modules/jooby-gradle-plugin/build.gradle | 2 +- .../java/io/jooby/jackson/JacksonModule.java | 18 +-- .../io/jooby/jackson3/Jackson3Module.java | 70 ++++----- modules/jooby-maven-plugin/pom.xml | 2 +- modules/jooby-trpc-avaje-jsonb/pom.xml | 29 ++++ .../trpc}/avaje/jsonb/AvajeTrpcDecoder.java | 4 +- .../trpc}/avaje/jsonb/AvajeTrpcParser.java | 8 +- .../trpc}/avaje/jsonb/AvajeTrpcReader.java | 6 +- .../avaje/jsonb/AvajeTrpcResponseAdapter.java | 4 +- .../avaje/jsonb/TrpcAvajeJsonbModule.java | 29 ++++ .../trpc/avaje/jsonb/TrpcJsonbExtension.java | 18 +++ .../io.avaje.jsonb.spi.JsonbExtension | 1 + modules/jooby-trpc-generator/pom.xml | 144 ++++++++++++++++++ .../java/io/jooby/trpc/TrpcGenerator.java | 18 +-- .../test/java/io/jooby/trpc/i3863/C3863.java | 1 + .../jooby/trpc/i3863/TrpcGeneratorTest.java | 0 .../test/java/io/jooby/trpc/i3863/U3863.java | 0 modules/jooby-trpc-jackson2/pom.xml | 28 ++++ .../trpc/jackson2}/JacksonTrpcDecoder.java | 4 +- .../trpc/jackson2}/JacksonTrpcParser.java | 8 +- .../trpc/jackson2}/JacksonTrpcReader.java | 6 +- .../JacksonTrpcResponseSerializer.java | 8 +- .../trpc/jackson2/TrpcJackson2Module.java | 28 ++++ .../src/main/java/module-info.java | 9 ++ modules/jooby-trpc-jackson3/pom.xml | 29 ++++ .../trpc}/jackson3/JacksonTrpcDecoder.java | 4 +- .../trpc}/jackson3/JacksonTrpcParser.java | 14 +- .../trpc}/jackson3/JacksonTrpcReader.java | 10 +- .../JacksonTrpcResponseSerializer.java | 4 +- .../trpc/jackson3/TrpcJackson3Module.java | 41 +++++ .../src/main/java/module-info.java | 10 ++ modules/jooby-trpc/pom.xml | 12 -- .../java/io/jooby/annotation/trpc}/Trpc.java | 12 +- .../main/java/io/jooby}/trpc/TrpcDecoder.java | 2 +- .../java/io/jooby}/trpc/TrpcErrorCode.java | 2 +- .../java/io/jooby}/trpc/TrpcErrorHandler.java | 2 +- .../java/io/jooby}/trpc/TrpcException.java | 2 +- .../main/java/io/jooby}/trpc/TrpcModule.java | 2 +- .../main/java/io/jooby}/trpc/TrpcParser.java | 2 +- .../main/java/io/jooby}/trpc/TrpcReader.java | 2 +- .../java/io/jooby}/trpc/TrpcResponse.java | 2 +- .../jooby-trpc/src/main/java/module-info.java | 8 + modules/pom.xml | 4 + tests/pom.xml | 20 +++ .../jooby/i3863/AbstractTrpcProtocolTest.java | 4 +- .../io/jooby/i3863/AvajeTrpcProtocolTest.java | 2 + .../jooby/i3863/Jackson2TrpcProtocolTest.java | 2 + .../jooby/i3863/Jackson3TrpcProtocolTest.java | 2 + ...{MovieService.java => MovieServiceTs.java} | 3 +- .../java/io/jooby/i3868/MovieService.java | 1 - tests/src/test/kotlin/i3863/KMovieService.kt | 11 +- tests/src/test/kotlin/i3868/KtMovieService.kt | 2 +- 64 files changed, 597 insertions(+), 200 deletions(-) create mode 100644 modules/jooby-trpc-avaje-jsonb/pom.xml rename modules/{jooby-avaje-jsonb/src/main/java/io/jooby/internal => jooby-trpc-avaje-jsonb/src/main/java/io/jooby/internal/trpc}/avaje/jsonb/AvajeTrpcDecoder.java (87%) rename modules/{jooby-avaje-jsonb/src/main/java/io/jooby/internal => jooby-trpc-avaje-jsonb/src/main/java/io/jooby/internal/trpc}/avaje/jsonb/AvajeTrpcParser.java (84%) rename modules/{jooby-avaje-jsonb/src/main/java/io/jooby/internal => jooby-trpc-avaje-jsonb/src/main/java/io/jooby/internal/trpc}/avaje/jsonb/AvajeTrpcReader.java (95%) rename modules/{jooby-avaje-jsonb/src/main/java/io/jooby/internal => jooby-trpc-avaje-jsonb/src/main/java/io/jooby/internal/trpc}/avaje/jsonb/AvajeTrpcResponseAdapter.java (93%) create mode 100644 modules/jooby-trpc-avaje-jsonb/src/main/java/io/jooby/trpc/avaje/jsonb/TrpcAvajeJsonbModule.java create mode 100644 modules/jooby-trpc-avaje-jsonb/src/main/java/io/jooby/trpc/avaje/jsonb/TrpcJsonbExtension.java create mode 100644 modules/jooby-trpc-avaje-jsonb/src/main/resources/META-INF/services/io.avaje.jsonb.spi.JsonbExtension create mode 100644 modules/jooby-trpc-generator/pom.xml rename modules/{jooby-trpc => jooby-trpc-generator}/src/main/java/io/jooby/trpc/TrpcGenerator.java (97%) rename modules/{jooby-trpc => jooby-trpc-generator}/src/test/java/io/jooby/trpc/i3863/C3863.java (95%) rename modules/{jooby-trpc => jooby-trpc-generator}/src/test/java/io/jooby/trpc/i3863/TrpcGeneratorTest.java (100%) rename modules/{jooby-trpc => jooby-trpc-generator}/src/test/java/io/jooby/trpc/i3863/U3863.java (100%) create mode 100644 modules/jooby-trpc-jackson2/pom.xml rename modules/{jooby-jackson/src/main/java/io/jooby/internal/jackson => jooby-trpc-jackson2/src/main/java/io/jooby/internal/trpc/jackson2}/JacksonTrpcDecoder.java (91%) rename modules/{jooby-jackson/src/main/java/io/jooby/internal/jackson => jooby-trpc-jackson2/src/main/java/io/jooby/internal/trpc/jackson2}/JacksonTrpcParser.java (89%) rename modules/{jooby-jackson/src/main/java/io/jooby/internal/jackson => jooby-trpc-jackson2/src/main/java/io/jooby/internal/trpc/jackson2}/JacksonTrpcReader.java (96%) rename modules/{jooby-jackson/src/main/java/io/jooby/internal/jackson => jooby-trpc-jackson2/src/main/java/io/jooby/internal/trpc/jackson2}/JacksonTrpcResponseSerializer.java (85%) create mode 100644 modules/jooby-trpc-jackson2/src/main/java/io/jooby/trpc/jackson2/TrpcJackson2Module.java create mode 100644 modules/jooby-trpc-jackson2/src/main/java/module-info.java create mode 100644 modules/jooby-trpc-jackson3/pom.xml rename modules/{jooby-jackson3/src/main/java/io/jooby/internal => jooby-trpc-jackson3/src/main/java/io/jooby/internal/trpc}/jackson3/JacksonTrpcDecoder.java (88%) rename modules/{jooby-jackson3/src/main/java/io/jooby/internal => jooby-trpc-jackson3/src/main/java/io/jooby/internal/trpc}/jackson3/JacksonTrpcParser.java (81%) rename modules/{jooby-jackson3/src/main/java/io/jooby/internal => jooby-trpc-jackson3/src/main/java/io/jooby/internal/trpc}/jackson3/JacksonTrpcReader.java (91%) rename modules/{jooby-jackson3/src/main/java/io/jooby/internal => jooby-trpc-jackson3/src/main/java/io/jooby/internal/trpc}/jackson3/JacksonTrpcResponseSerializer.java (92%) create mode 100644 modules/jooby-trpc-jackson3/src/main/java/io/jooby/trpc/jackson3/TrpcJackson3Module.java create mode 100644 modules/jooby-trpc-jackson3/src/main/java/module-info.java rename {jooby/src/main/java/io/jooby/annotation => modules/jooby-trpc/src/main/java/io/jooby/annotation/trpc}/Trpc.java (88%) rename {jooby/src/main/java/io/jooby/rpc => modules/jooby-trpc/src/main/java/io/jooby}/trpc/TrpcDecoder.java (98%) rename {jooby/src/main/java/io/jooby/rpc => modules/jooby-trpc/src/main/java/io/jooby}/trpc/TrpcErrorCode.java (99%) rename {jooby/src/main/java/io/jooby/rpc => modules/jooby-trpc/src/main/java/io/jooby}/trpc/TrpcErrorHandler.java (99%) rename {jooby/src/main/java/io/jooby/rpc => modules/jooby-trpc/src/main/java/io/jooby}/trpc/TrpcException.java (99%) rename {jooby/src/main/java/io/jooby/rpc => modules/jooby-trpc/src/main/java/io/jooby}/trpc/TrpcModule.java (98%) rename {jooby/src/main/java/io/jooby/rpc => modules/jooby-trpc/src/main/java/io/jooby}/trpc/TrpcParser.java (99%) rename {jooby/src/main/java/io/jooby/rpc => modules/jooby-trpc/src/main/java/io/jooby}/trpc/TrpcReader.java (99%) rename {jooby/src/main/java/io/jooby/rpc => modules/jooby-trpc/src/main/java/io/jooby}/trpc/TrpcResponse.java (98%) create mode 100644 modules/jooby-trpc/src/main/java/module-info.java rename tests/src/test/java/io/jooby/i3863/{MovieService.java => MovieServiceTs.java} (97%) diff --git a/docs/asciidoc/tRPC.adoc b/docs/asciidoc/tRPC.adoc index 88fe7fb329..8cbd5f9fd9 100644 --- a/docs/asciidoc/tRPC.adoc +++ b/docs/asciidoc/tRPC.adoc @@ -2,28 +2,32 @@ The tRPC module provides end-to-end type safety by integrating the https://trpc.io/[tRPC] protocol directly into Jooby. -Because the `io.jooby.trpc` package is included in Jooby core, there are no extra dependencies to add to your project. This integration allows you to write standard Java/Kotlin controllers and consume them directly in the browser using the official `@trpc/client`—complete with 100% type safety, autocomplete, and zero manual client generation. +Because tRPC is provided in its own module, you will need to add the `jooby-trpc-*` dependencies to your project. This integration allows you to write standard Java/Kotlin controllers and consume them directly in the browser using the official `@trpc/client`—complete with 100% type safety, autocomplete, and zero manual client generation. -===== Usage +[dependency, artifactId="jooby-jackson3:Jackson Module, jooby-trpc-jackson3:Trpc Jackson Module, jooby-trpc:Trpc Module"] +. -Because tRPC relies heavily on JSON serialization to communicate with the frontend client, a JSON module **must** be installed prior to the `TrpcModule`. +===== Usage -NOTE: Currently, Jooby only provides the required `TrpcParser` SPI implementation for two JSON engines: **Jackson 2/3** and **AvajeJsonbModule**. Using other JSON modules (like Gson) will result in a missing service exception at startup. +Installing tRPC in your Jooby app is a 3-step process. Because tRPC relies heavily on JSON serialization to communicate with the frontend client, you must install a JSON module, followed by its corresponding tRPC bridge module, and finally the core `TrpcModule`. .Java [source,java,role="primary"] ---- import io.jooby.Jooby; import io.jooby.json.JacksonModule; -import io.jooby.rpc.trpc.TrpcModule; +import io.jooby.trpc.TrpcModule; +import io.jooby.trpc.TrpcJackson2Module; public class App extends Jooby { { - install(new JacksonModule()); // <1> + install(new Jackson3Module()); // <1> - install(new TrpcModule()); // <2> + install(new TrpcJackson3Module()); // <2> + + install(new TrpcModule()); // <3> - trpc(new MovieServiceTrpc_()); // <3> + trpc(new MovieServiceTrpc_()); // <4> } } ---- @@ -33,20 +37,24 @@ public class App extends Jooby { ---- import io.jooby.kt.Kooby import io.jooby.json.JacksonModule -import io.jooby.rpc.trpc.TrpcModule +import io.jooby.trpc.TrpcModule +import io.jooby.trpc.TrpcJackson2Module class App : Kooby({ - install(JacksonModule()) // <1> + install(Jackson3Module()) // <1> - install(TrpcModule()) // <2> + install(TrpcJackson3Module()) // <2> + + install(TrpcModule()) // <3> - trpc(MovieServiceTrpc_()) // <3> + trpc(MovieServiceTrpc_()) // <4> }) ---- -1. Install a supported JSON engine (Jackson or Avaje) -2. Install the tRPC extension -3. Register your @Trpc annotated controllers (using the APT generated route) +1. Install a supported JSON engine (`Jackson3Module`, `JacksonModule` for Jackson 2, or `AvajeJsonbModule`). +2. Install the corresponding bridge module (`TrcJackson3Module`, `TrpcJackson2Module`, or `TrpcAvajeJsonbModule`). +3. Install the core tRPC extension (`TrpcModule`). +4. Register your `@Trpc` annotated controllers (using the APT generated route). ===== Writing a Service @@ -58,7 +66,7 @@ You can define your procedures using explicit tRPC annotations or a hybrid appro .Java [source,java,role="primary"] ---- -import io.jooby.annotation.Trpc; +import io.jooby.annotation.trpc.Trpc; import io.jooby.annotation.DELETE; public record Movie(int id, String title, int year) {} @@ -91,7 +99,7 @@ public class MovieService { .Kotlin [source,kotlin,role="secondary"] ---- -import io.jooby.annotation.Trpc +import io.jooby.annotation.trpc.Trpc import io.jooby.annotation.DELETE data class Movie(val id: Int, val title: String, val year: Int) @@ -197,7 +205,8 @@ If you throw custom domain exceptions, you can map them directly to tRPC error c .Java [source,java,role="primary"] ---- -import io.jooby.rpc.trpc.TrpcErrorCode; +import io.jooby.trpc.TrpcModule; +import io.jooby.trpc.TrpcErrorCode; { install(new TrpcModule()); @@ -213,8 +222,8 @@ import io.jooby.rpc.trpc.TrpcErrorCode; [source,kotlin,role="secondary"] ---- import io.jooby.kt.Kooby -import io.jooby.rpc.trpc.TrpcModule -import io.jooby.rpc.trpc.TrpcErrorCode +import io.jooby.trpc.TrpcModule +import io.jooby.trpc.TrpcErrorCode class App : Kooby({ install(TrpcModule()) diff --git a/jooby/src/main/java/module-info.java b/jooby/src/main/java/module-info.java index ce4d5c509e..b1d272d352 100644 --- a/jooby/src/main/java/module-info.java +++ b/jooby/src/main/java/module-info.java @@ -17,7 +17,6 @@ /* rpc */ exports io.jooby.rpc.jsonrpc; exports io.jooby.rpc.grpc; - exports io.jooby.rpc.trpc; uses io.jooby.Server; uses io.jooby.SslProvider; diff --git a/modules/jooby-apt/pom.xml b/modules/jooby-apt/pom.xml index 02db8572a2..ad1f0f2149 100644 --- a/modules/jooby-apt/pom.xml +++ b/modules/jooby-apt/pom.xml @@ -38,6 +38,13 @@ test + + io.jooby + jooby-trpc + ${jooby.version} + test + + com.github.victools jsonschema-generator diff --git a/modules/jooby-apt/src/main/java/io/jooby/apt/JoobyProcessor.java b/modules/jooby-apt/src/main/java/io/jooby/apt/JoobyProcessor.java index 2553d7b226..33dcc96e37 100644 --- a/modules/jooby-apt/src/main/java/io/jooby/apt/JoobyProcessor.java +++ b/modules/jooby-apt/src/main/java/io/jooby/apt/JoobyProcessor.java @@ -266,9 +266,9 @@ public Set getSupportedAnnotationTypes() { supportedTypes.addAll(HttpPath.PATH.getAnnotations()); supportedTypes.addAll(HttpMethod.annotations()); // Add Rcp annotations - supportedTypes.add("io.jooby.annotation.Trpc"); - supportedTypes.add("io.jooby.annotation.Trpc.Mutation"); - supportedTypes.add("io.jooby.annotation.Trpc.Query"); + supportedTypes.add("io.jooby.annotation.trpc.Trpc"); + supportedTypes.add("io.jooby.annotation.trpc.Trpc.Mutation"); + supportedTypes.add("io.jooby.annotation.trpc.Trpc.Query"); supportedTypes.add("io.jooby.annotation.JsonRpc"); // Add MCP Annotations supportedTypes.add("io.jooby.annotation.mcp.McpCompletion"); diff --git a/modules/jooby-apt/src/main/java/io/jooby/internal/apt/TrpcRoute.java b/modules/jooby-apt/src/main/java/io/jooby/internal/apt/TrpcRoute.java index 5c21b564bb..917cd3e63c 100644 --- a/modules/jooby-apt/src/main/java/io/jooby/internal/apt/TrpcRoute.java +++ b/modules/jooby-apt/src/main/java/io/jooby/internal/apt/TrpcRoute.java @@ -30,11 +30,11 @@ public void setGeneratedName(String generatedName) { } private HttpMethod discoverTrpcMethod() { - if (AnnotationSupport.findAnnotationByName(method, "io.jooby.annotation.Trpc.Query") != null) - return HttpMethod.GET; - if (AnnotationSupport.findAnnotationByName(method, "io.jooby.annotation.Trpc.Mutation") != null) - return HttpMethod.POST; - if (AnnotationSupport.findAnnotationByName(method, "io.jooby.annotation.Trpc") != null) { + if (AnnotationSupport.findAnnotationByName(method, "io.jooby.annotation.trpc.Trpc.Query") + != null) return HttpMethod.GET; + if (AnnotationSupport.findAnnotationByName(method, "io.jooby.annotation.trpc.Trpc.Mutation") + != null) return HttpMethod.POST; + if (AnnotationSupport.findAnnotationByName(method, "io.jooby.annotation.trpc.Trpc") != null) { if (HttpMethod.GET.matches(method)) return HttpMethod.GET; return HttpMethod.POST; } @@ -45,16 +45,16 @@ private String trpcPath() { var namespace = Optional.ofNullable( AnnotationSupport.findAnnotationByName( - method.getEnclosingElement(), "io.jooby.annotation.Trpc")) + method.getEnclosingElement(), "io.jooby.annotation.trpc.Trpc")) .flatMap(it -> AnnotationSupport.findAnnotationValue(it, VALUE).stream().findFirst()) .map(it -> it + ".") .orElse(""); var procedure = Stream.of( - "io.jooby.annotation.Trpc.Query", - "io.jooby.annotation.Trpc.Mutation", - "io.jooby.annotation.Trpc") + "io.jooby.annotation.trpc.Trpc.Query", + "io.jooby.annotation.trpc.Trpc.Mutation", + "io.jooby.annotation.trpc.Trpc") .map(it -> AnnotationSupport.findAnnotationByName(method, it)) .filter(Objects::nonNull) .findFirst() @@ -138,10 +138,10 @@ public List generateHandlerCall(boolean kt) { innerReactiveType = kt ? "Unit" : "Void"; } methodReturnTypeString = - rawReactiveType + ">"; + rawReactiveType + ">"; } else { methodReturnTypeString = - "io.jooby.rpc.trpc.TrpcResponse<" + "io.jooby.trpc.TrpcResponse<" + (returnType.isVoid() ? (kt ? "Unit" : "Void") : returnTypeString) + ">"; } @@ -173,7 +173,7 @@ public List generateHandlerCall(boolean kt) { statement( indent(2), var(kt), - "parser = ctx.require(io.jooby.rpc.trpc.TrpcParser", + "parser = ctx.require(io.jooby.trpc.TrpcParser", clazz(kt), ")", semicolon(kt))); @@ -433,7 +433,7 @@ public List generateHandlerCall(boolean kt) { indent(4), "val ", parameterName, - "Decoder: io.jooby.rpc.trpc.TrpcDecoder<", + "Decoder: io.jooby.trpc.TrpcDecoder<", type, "> = parser.decoder(", parameter.getType().toSourceCode(kt), @@ -467,7 +467,7 @@ public List generateHandlerCall(boolean kt) { buffer.add( statement( indent(4), - "io.jooby.rpc.trpc.TrpcDecoder<", + "io.jooby.trpc.TrpcDecoder<", genericType, "> ", parameterName, @@ -527,7 +527,7 @@ public List generateHandlerCall(boolean kt) { indent(controllerIndent), "return ", call, - ".then(reactor.core.publisher.Mono.just(io.jooby.rpc.trpc.TrpcResponse.empty()))", + ".then(reactor.core.publisher.Mono.just(io.jooby.trpc.TrpcResponse.empty()))", semicolon(kt))); } else if (handler.contains("Mutiny")) { buffer.add( @@ -535,7 +535,7 @@ public List generateHandlerCall(boolean kt) { indent(controllerIndent), "return ", call, - ".replaceWith(io.jooby.rpc.trpc.TrpcResponse.empty())", + ".replaceWith(io.jooby.trpc.TrpcResponse.empty())", semicolon(kt))); } else if (handler.contains("ReactiveSupport")) { buffer.add( @@ -543,7 +543,7 @@ public List generateHandlerCall(boolean kt) { indent(controllerIndent), "return ", call, - ".thenApply(x -> io.jooby.rpc.trpc.TrpcResponse.empty())", + ".thenApply(x -> io.jooby.trpc.TrpcResponse.empty())", semicolon(kt))); } else if (handler.contains("Reactivex")) { buffer.add( @@ -551,7 +551,7 @@ public List generateHandlerCall(boolean kt) { indent(controllerIndent), "return ", call, - ".toSingleDefault(io.jooby.rpc.trpc.TrpcResponse.empty())", + ".toSingleDefault(io.jooby.trpc.TrpcResponse.empty())", semicolon(kt))); } else { buffer.add( @@ -559,7 +559,7 @@ public List generateHandlerCall(boolean kt) { indent(controllerIndent), "return ", call, - ".map(x -> io.jooby.rpc.trpc.TrpcResponse.empty())", + ".map(x -> io.jooby.trpc.TrpcResponse.empty())", semicolon(kt))); } } else { @@ -570,7 +570,7 @@ public List generateHandlerCall(boolean kt) { indent(controllerIndent), "return ", call, - ".map { io.jooby.rpc.trpc.TrpcResponse.of(it) }")); + ".map { io.jooby.trpc.TrpcResponse.of(it) }")); } else { if (handler.contains("ReactiveSupport")) { buffer.add( @@ -578,7 +578,7 @@ public List generateHandlerCall(boolean kt) { indent(controllerIndent), "return ", call, - ".thenApply(io.jooby.rpc.trpc.TrpcResponse::of)", + ".thenApply(io.jooby.trpc.TrpcResponse::of)", semicolon(kt))); } else if (handler.contains("Mutiny")) { buffer.add( @@ -586,7 +586,7 @@ public List generateHandlerCall(boolean kt) { indent(controllerIndent), "return ", call, - ".onItem().transform(io.jooby.rpc.trpc.TrpcResponse::of)", + ".onItem().transform(io.jooby.trpc.TrpcResponse::of)", semicolon(kt))); } else { // Reactor (Mono), RxJava (Single), etc. @@ -595,7 +595,7 @@ public List generateHandlerCall(boolean kt) { indent(controllerIndent), "return ", call, - ".map(io.jooby.rpc.trpc.TrpcResponse::of)", + ".map(io.jooby.trpc.TrpcResponse::of)", semicolon(kt))); } } @@ -605,13 +605,13 @@ public List generateHandlerCall(boolean kt) { buffer.add( statement( indent(controllerIndent), - "return io.jooby.rpc.trpc.TrpcResponse.empty()", + "return io.jooby.trpc.TrpcResponse.empty()", semicolon(kt))); } else { buffer.add( statement( indent(controllerIndent), - "return io.jooby.rpc.trpc.TrpcResponse.of(", + "return io.jooby.trpc.TrpcResponse.of(", call, nullable ? "!!" : "", // Shared nullability check ")", diff --git a/modules/jooby-apt/src/main/java/io/jooby/internal/apt/TrpcRouter.java b/modules/jooby-apt/src/main/java/io/jooby/internal/apt/TrpcRouter.java index e002c35b78..d3834303c3 100644 --- a/modules/jooby-apt/src/main/java/io/jooby/internal/apt/TrpcRouter.java +++ b/modules/jooby-apt/src/main/java/io/jooby/internal/apt/TrpcRouter.java @@ -34,10 +34,13 @@ public static TrpcRouter parse(MvcContext context, TypeElement controller) { continue; } - if (AnnotationSupport.findAnnotationByName(method, "io.jooby.annotation.Trpc") != null - || AnnotationSupport.findAnnotationByName(method, "io.jooby.annotation.Trpc.Query") + if (AnnotationSupport.findAnnotationByName(method, "io.jooby.annotation.trpc.Trpc") != null - || AnnotationSupport.findAnnotationByName(method, "io.jooby.annotation.Trpc.Mutation") + || AnnotationSupport.findAnnotationByName( + method, "io.jooby.annotation.trpc.Trpc.Query") + != null + || AnnotationSupport.findAnnotationByName( + method, "io.jooby.annotation.trpc.Trpc.Mutation") != null) { TrpcRoute route = new TrpcRoute(router, method); diff --git a/modules/jooby-apt/src/test/java/tests/i3863/MixedMutation.java b/modules/jooby-apt/src/test/java/tests/i3863/MixedMutation.java index 4d8300625a..8c90b98247 100644 --- a/modules/jooby-apt/src/test/java/tests/i3863/MixedMutation.java +++ b/modules/jooby-apt/src/test/java/tests/i3863/MixedMutation.java @@ -6,6 +6,7 @@ package tests.i3863; import io.jooby.annotation.*; +import io.jooby.annotation.trpc.Trpc; @Trpc("users") public class MixedMutation { diff --git a/modules/jooby-apt/src/test/java/tests/i3863/MixedTrpcAnnotation.java b/modules/jooby-apt/src/test/java/tests/i3863/MixedTrpcAnnotation.java index d0618e8d02..11c4513579 100644 --- a/modules/jooby-apt/src/test/java/tests/i3863/MixedTrpcAnnotation.java +++ b/modules/jooby-apt/src/test/java/tests/i3863/MixedTrpcAnnotation.java @@ -7,6 +7,7 @@ import io.jooby.Context; import io.jooby.annotation.*; +import io.jooby.annotation.trpc.Trpc; @Trpc("users") @Path("/api/users") diff --git a/modules/jooby-apt/src/test/java/tests/i3863/OverloadTrpc.java b/modules/jooby-apt/src/test/java/tests/i3863/OverloadTrpc.java index d8449da16c..761c2bc6ea 100644 --- a/modules/jooby-apt/src/test/java/tests/i3863/OverloadTrpc.java +++ b/modules/jooby-apt/src/test/java/tests/i3863/OverloadTrpc.java @@ -5,7 +5,7 @@ */ package tests.i3863; -import io.jooby.annotation.Trpc; +import io.jooby.annotation.trpc.Trpc; @Trpc("users") public class OverloadTrpc { diff --git a/modules/jooby-apt/src/test/java/tests/i3863/SpecificTrpcAnnotation.java b/modules/jooby-apt/src/test/java/tests/i3863/SpecificTrpcAnnotation.java index 7b61b891ca..fc4d865f02 100644 --- a/modules/jooby-apt/src/test/java/tests/i3863/SpecificTrpcAnnotation.java +++ b/modules/jooby-apt/src/test/java/tests/i3863/SpecificTrpcAnnotation.java @@ -6,7 +6,7 @@ package tests.i3863; import io.jooby.Context; -import io.jooby.annotation.Trpc; +import io.jooby.annotation.trpc.Trpc; @Trpc("users") public class SpecificTrpcAnnotation { diff --git a/modules/jooby-apt/src/test/java/tests/i3863/TopLevelTrpcDoesNothingByItSelf.java b/modules/jooby-apt/src/test/java/tests/i3863/TopLevelTrpcDoesNothingByItSelf.java index 0df25fada1..58fc486248 100644 --- a/modules/jooby-apt/src/test/java/tests/i3863/TopLevelTrpcDoesNothingByItSelf.java +++ b/modules/jooby-apt/src/test/java/tests/i3863/TopLevelTrpcDoesNothingByItSelf.java @@ -6,7 +6,7 @@ package tests.i3863; import io.jooby.Context; -import io.jooby.annotation.Trpc; +import io.jooby.annotation.trpc.Trpc; @Trpc("users") public class TopLevelTrpcDoesNothingByItSelf { diff --git a/modules/jooby-avaje-jsonb/src/main/java/io/jooby/avaje/jsonb/AvajeJsonbModule.java b/modules/jooby-avaje-jsonb/src/main/java/io/jooby/avaje/jsonb/AvajeJsonbModule.java index e9543b3842..5875fa96c5 100644 --- a/modules/jooby-avaje-jsonb/src/main/java/io/jooby/avaje/jsonb/AvajeJsonbModule.java +++ b/modules/jooby-avaje-jsonb/src/main/java/io/jooby/avaje/jsonb/AvajeJsonbModule.java @@ -10,7 +10,6 @@ import java.util.*; import edu.umd.cs.findbugs.annotations.NonNull; -import io.avaje.json.JsonDataException; import io.avaje.json.JsonWriter; import io.avaje.jsonb.JsonView; import io.avaje.jsonb.Jsonb; @@ -20,9 +19,6 @@ import io.jooby.rpc.jsonrpc.JsonRpcParser; import io.jooby.rpc.jsonrpc.JsonRpcRequest; import io.jooby.rpc.jsonrpc.JsonRpcResponse; -import io.jooby.rpc.trpc.TrpcErrorCode; -import io.jooby.rpc.trpc.TrpcParser; -import io.jooby.rpc.trpc.TrpcResponse; /** * JSON module using Avaje-JsonB: projected) { public static Jsonb.Builder builder() { var jsonb = Jsonb.builder(); - jsonb.add(TrpcResponse.class, AvajeTrpcResponseAdapter::new); jsonb.add(JsonRpcRequest.class, AvajeJsonRpcRequestAdapter::new); jsonb.add(JsonRpcResponse.class, AvajeJsonRpcResponseAdapter::new); jsonb.add(JsonRpcResponse.ErrorDetail.class, AvajeJsonRpcErrorAdapter::new); diff --git a/modules/jooby-gradle-plugin/build.gradle b/modules/jooby-gradle-plugin/build.gradle index 70f69d5f3e..225c04ad6b 100644 --- a/modules/jooby-gradle-plugin/build.gradle +++ b/modules/jooby-gradle-plugin/build.gradle @@ -26,7 +26,7 @@ group = "io.jooby" dependencies { implementation "io.jooby:jooby-run:$version" implementation "io.jooby:jooby-openapi:$version" - implementation "io.jooby:jooby-trpc:$version" + implementation "io.jooby:jooby-trpc-generator:$version" implementation "com.github.spotbugs:spotbugs-annotations:4.7.2" } diff --git a/modules/jooby-jackson/src/main/java/io/jooby/jackson/JacksonModule.java b/modules/jooby-jackson/src/main/java/io/jooby/jackson/JacksonModule.java index 5cae4e6464..551c4b7b89 100644 --- a/modules/jooby-jackson/src/main/java/io/jooby/jackson/JacksonModule.java +++ b/modules/jooby-jackson/src/main/java/io/jooby/jackson/JacksonModule.java @@ -7,10 +7,7 @@ import java.io.InputStream; import java.lang.reflect.Type; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Stream; @@ -34,8 +31,6 @@ import io.jooby.rpc.jsonrpc.JsonRpcParser; import io.jooby.rpc.jsonrpc.JsonRpcRequest; import io.jooby.rpc.jsonrpc.JsonRpcResponse; -import io.jooby.rpc.trpc.TrpcParser; -import io.jooby.rpc.trpc.TrpcResponse; /** * JSON module using Jackson: https://jooby.io/modules/jackson2. @@ -155,9 +150,6 @@ public void install(@NonNull Jooby application) { application.errorCode(JsonParseException.class, StatusCode.BAD_REQUEST); application.errorCode(MismatchedInputException.class, StatusCode.BAD_REQUEST); - // tRPC - services.put(TrpcParser.class, new JacksonTrpcParser(mapper)); - // JSON-RPC services.put(JsonRpcParser.class, new JacksonJsonRpcParser(mapper)); services @@ -179,6 +171,13 @@ public void install(@NonNull Jooby application) { Module module = application.require(type); mapper.registerModule(module); } + List moreModules = + application.getServices().getOrNull(Reified.list(Module.class)); + if (moreModules != null) { + for (Module module : moreModules) { + mapper.registerModule(module); + } + } }); } @@ -238,7 +237,6 @@ public static ObjectMapper create(Module... modules) { Stream.of(modules).forEach(builder::addModule); // RPC var rpc = new SimpleModule(); - rpc.addSerializer(TrpcResponse.class, new JacksonTrpcResponseSerializer()); rpc.addDeserializer(JsonRpcRequest.class, new JacksonJsonRpcRequestDeserializer()); rpc.addSerializer(JsonRpcResponse.class, new JacksonJsonRpcResponseSerializer()); builder.addModule(rpc); diff --git a/modules/jooby-jackson3/src/main/java/io/jooby/jackson3/Jackson3Module.java b/modules/jooby-jackson3/src/main/java/io/jooby/jackson3/Jackson3Module.java index 511d1725d9..b28c608fd8 100644 --- a/modules/jooby-jackson3/src/main/java/io/jooby/jackson3/Jackson3Module.java +++ b/modules/jooby-jackson3/src/main/java/io/jooby/jackson3/Jackson3Module.java @@ -7,10 +7,7 @@ import java.io.InputStream; import java.lang.reflect.Type; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Stream; @@ -23,9 +20,6 @@ import io.jooby.rpc.jsonrpc.JsonRpcParser; import io.jooby.rpc.jsonrpc.JsonRpcRequest; import io.jooby.rpc.jsonrpc.JsonRpcResponse; -import io.jooby.rpc.trpc.TrpcErrorCode; -import io.jooby.rpc.trpc.TrpcParser; -import io.jooby.rpc.trpc.TrpcResponse; import tools.jackson.core.exc.StreamReadException; import tools.jackson.databind.*; import tools.jackson.databind.exc.MismatchedInputException; @@ -84,7 +78,7 @@ public class Jackson3Module implements Extension, MessageDecoder, MessageEncoder private final MediaType mediaType; - private final ObjectMapper mapper; + private ObjectMapper mapper; private ObjectMapper projectionMapper; private final TypeFactory typeFactory; @@ -139,22 +133,12 @@ public Jackson3Module module(Class module) { } @Override - @SuppressWarnings({"rawtypes", "unchecked"}) public void install(@NonNull Jooby application) { application.decoder(mediaType, this); application.encoder(mediaType, this); - ServiceRegistry services = application.getServices(); - Class mapperType = mapper.getClass(); - services.put(mapperType, mapper); - services.put(ObjectMapper.class, mapper); - // tRPC - services.put(TrpcParser.class, new JacksonTrpcParser(mapper)); - services - .mapOf(Class.class, TrpcErrorCode.class) - .put(StreamReadException.class, TrpcErrorCode.BAD_REQUEST) - .put(MismatchedInputException.class, TrpcErrorCode.BAD_REQUEST) - .put(DatabindException.class, TrpcErrorCode.BAD_REQUEST); + var services = application.getServices(); + bindMapper(services, mapper); // JSON-RPC services.put(JsonRpcParser.class, new JacksonJsonRpcParser(mapper)); @@ -168,26 +152,43 @@ public void install(@NonNull Jooby application) { application.errorCode(StreamReadException.class, StatusCode.BAD_REQUEST); application.errorCode(DatabindException.class, StatusCode.BAD_REQUEST); - application.onStarting(() -> onStarting(application, services, mapperType)); - - // 2. Branch off a specialized mapper JUST for Projections. - // .rebuild() copies the user's configuration, and we add our global MixIn - // strictly to this specialized instance. - projectionMapper = mapper.rebuild().addMixIn(Object.class, ProjectionMixIn.class).build(); + application.onStarting(() -> onStarting(application, services)); } @SuppressWarnings({"rawtypes", "unchecked"}) - private void onStarting(Jooby application, ServiceRegistry services, Class mapperType) { + private void bindMapper(ServiceRegistry services, ObjectMapper mapper) { + Class mapperType = mapper.getClass(); + services.put(mapperType, this.mapper); + services.put(ObjectMapper.class, this.mapper); + } + + private void onStarting(Jooby application, ServiceRegistry services) { + var finalMapper = this.mapper; + var modules = computeModules(application); if (!modules.isEmpty()) { var builder = mapper.rebuild(); - for (Class type : modules) { - JacksonModule module = application.require(type); - builder.addModule(module); - } - var newMapper = builder.build(); - services.put(mapperType, newMapper); - services.put(ObjectMapper.class, newMapper); + modules.forEach(builder::addModule); + // re-bind + finalMapper = builder.build(); + this.mapper = finalMapper; + bindMapper(services, finalMapper); + } + // Branch off a specialized mapper JUST for Projections. + projectionMapper = finalMapper.rebuild().addMixIn(Object.class, ProjectionMixIn.class).build(); + } + + private List computeModules(Jooby application) { + List result = new ArrayList<>(); + for (Class type : modules) { + var module = application.require(type); + result.add(module); + } + List moreModules = + application.getServices().getOrNull(Reified.list(JacksonModule.class)); + if (moreModules != null) { + result.addAll(moreModules); } + return result; } @Override @@ -241,7 +242,6 @@ public static JsonMapper create(JacksonModule... modules) { Stream.of(modules).forEach(builder::addModule); var rpcModule = new SimpleModule(); - rpcModule.addSerializer(TrpcResponse.class, new JacksonTrpcResponseSerializer()); rpcModule.addSerializer(JsonRpcResponse.class, new JacksonJsonRpcResponseSerializer()); rpcModule.addDeserializer(JsonRpcRequest.class, new JacksonJsonRpcRequestDeserializer()); builder.addModule(rpcModule); diff --git a/modules/jooby-maven-plugin/pom.xml b/modules/jooby-maven-plugin/pom.xml index c6a0ad5a72..c12636e919 100644 --- a/modules/jooby-maven-plugin/pom.xml +++ b/modules/jooby-maven-plugin/pom.xml @@ -31,7 +31,7 @@ io.jooby - jooby-trpc + jooby-trpc-generator ${jooby.version} diff --git a/modules/jooby-trpc-avaje-jsonb/pom.xml b/modules/jooby-trpc-avaje-jsonb/pom.xml new file mode 100644 index 0000000000..a3bb360e42 --- /dev/null +++ b/modules/jooby-trpc-avaje-jsonb/pom.xml @@ -0,0 +1,29 @@ + + + 4.0.0 + + io.jooby + modules + 4.2.1-SNAPSHOT + + + jooby-trpc-avaje-jsonb + jooby-trpc-avaje-jsonb + + + + io.jooby + jooby-trpc + ${jooby.version} + + + + io.jooby + jooby-avaje-jsonb + ${jooby.version} + + + + diff --git a/modules/jooby-avaje-jsonb/src/main/java/io/jooby/internal/avaje/jsonb/AvajeTrpcDecoder.java b/modules/jooby-trpc-avaje-jsonb/src/main/java/io/jooby/internal/trpc/avaje/jsonb/AvajeTrpcDecoder.java similarity index 87% rename from modules/jooby-avaje-jsonb/src/main/java/io/jooby/internal/avaje/jsonb/AvajeTrpcDecoder.java rename to modules/jooby-trpc-avaje-jsonb/src/main/java/io/jooby/internal/trpc/avaje/jsonb/AvajeTrpcDecoder.java index a318e838aa..d473b8ec6b 100644 --- a/modules/jooby-avaje-jsonb/src/main/java/io/jooby/internal/avaje/jsonb/AvajeTrpcDecoder.java +++ b/modules/jooby-trpc-avaje-jsonb/src/main/java/io/jooby/internal/trpc/avaje/jsonb/AvajeTrpcDecoder.java @@ -3,10 +3,10 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.internal.avaje.jsonb; +package io.jooby.internal.trpc.avaje.jsonb; import io.avaje.jsonb.JsonType; -import io.jooby.rpc.trpc.TrpcDecoder; +import io.jooby.trpc.TrpcDecoder; public class AvajeTrpcDecoder implements TrpcDecoder { diff --git a/modules/jooby-avaje-jsonb/src/main/java/io/jooby/internal/avaje/jsonb/AvajeTrpcParser.java b/modules/jooby-trpc-avaje-jsonb/src/main/java/io/jooby/internal/trpc/avaje/jsonb/AvajeTrpcParser.java similarity index 84% rename from modules/jooby-avaje-jsonb/src/main/java/io/jooby/internal/avaje/jsonb/AvajeTrpcParser.java rename to modules/jooby-trpc-avaje-jsonb/src/main/java/io/jooby/internal/trpc/avaje/jsonb/AvajeTrpcParser.java index 1c95ad4bae..2ea51001b0 100644 --- a/modules/jooby-avaje-jsonb/src/main/java/io/jooby/internal/avaje/jsonb/AvajeTrpcParser.java +++ b/modules/jooby-trpc-avaje-jsonb/src/main/java/io/jooby/internal/trpc/avaje/jsonb/AvajeTrpcParser.java @@ -3,14 +3,14 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.internal.avaje.jsonb; +package io.jooby.internal.trpc.avaje.jsonb; import java.lang.reflect.Type; import io.avaje.jsonb.Jsonb; -import io.jooby.rpc.trpc.TrpcDecoder; -import io.jooby.rpc.trpc.TrpcParser; -import io.jooby.rpc.trpc.TrpcReader; +import io.jooby.trpc.TrpcDecoder; +import io.jooby.trpc.TrpcParser; +import io.jooby.trpc.TrpcReader; public class AvajeTrpcParser implements TrpcParser { diff --git a/modules/jooby-avaje-jsonb/src/main/java/io/jooby/internal/avaje/jsonb/AvajeTrpcReader.java b/modules/jooby-trpc-avaje-jsonb/src/main/java/io/jooby/internal/trpc/avaje/jsonb/AvajeTrpcReader.java similarity index 95% rename from modules/jooby-avaje-jsonb/src/main/java/io/jooby/internal/avaje/jsonb/AvajeTrpcReader.java rename to modules/jooby-trpc-avaje-jsonb/src/main/java/io/jooby/internal/trpc/avaje/jsonb/AvajeTrpcReader.java index 362d89ab97..da12eada4b 100644 --- a/modules/jooby-avaje-jsonb/src/main/java/io/jooby/internal/avaje/jsonb/AvajeTrpcReader.java +++ b/modules/jooby-trpc-avaje-jsonb/src/main/java/io/jooby/internal/trpc/avaje/jsonb/AvajeTrpcReader.java @@ -3,12 +3,12 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.internal.avaje.jsonb; +package io.jooby.internal.trpc.avaje.jsonb; import io.avaje.json.JsonReader; import io.jooby.exception.MissingValueException; -import io.jooby.rpc.trpc.TrpcDecoder; -import io.jooby.rpc.trpc.TrpcReader; +import io.jooby.trpc.TrpcDecoder; +import io.jooby.trpc.TrpcReader; public class AvajeTrpcReader implements TrpcReader { private final JsonReader reader; diff --git a/modules/jooby-avaje-jsonb/src/main/java/io/jooby/internal/avaje/jsonb/AvajeTrpcResponseAdapter.java b/modules/jooby-trpc-avaje-jsonb/src/main/java/io/jooby/internal/trpc/avaje/jsonb/AvajeTrpcResponseAdapter.java similarity index 93% rename from modules/jooby-avaje-jsonb/src/main/java/io/jooby/internal/avaje/jsonb/AvajeTrpcResponseAdapter.java rename to modules/jooby-trpc-avaje-jsonb/src/main/java/io/jooby/internal/trpc/avaje/jsonb/AvajeTrpcResponseAdapter.java index baa479f733..452feb3099 100644 --- a/modules/jooby-avaje-jsonb/src/main/java/io/jooby/internal/avaje/jsonb/AvajeTrpcResponseAdapter.java +++ b/modules/jooby-trpc-avaje-jsonb/src/main/java/io/jooby/internal/trpc/avaje/jsonb/AvajeTrpcResponseAdapter.java @@ -3,13 +3,13 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.internal.avaje.jsonb; +package io.jooby.internal.trpc.avaje.jsonb; import io.avaje.json.JsonAdapter; import io.avaje.json.JsonReader; import io.avaje.json.JsonWriter; import io.avaje.jsonb.Jsonb; -import io.jooby.rpc.trpc.TrpcResponse; +import io.jooby.trpc.TrpcResponse; public class AvajeTrpcResponseAdapter implements JsonAdapter { diff --git a/modules/jooby-trpc-avaje-jsonb/src/main/java/io/jooby/trpc/avaje/jsonb/TrpcAvajeJsonbModule.java b/modules/jooby-trpc-avaje-jsonb/src/main/java/io/jooby/trpc/avaje/jsonb/TrpcAvajeJsonbModule.java new file mode 100644 index 0000000000..bc272085b3 --- /dev/null +++ b/modules/jooby-trpc-avaje-jsonb/src/main/java/io/jooby/trpc/avaje/jsonb/TrpcAvajeJsonbModule.java @@ -0,0 +1,29 @@ +/* + * Jooby https://jooby.io + * Apache License Version 2.0 https://jooby.io/LICENSE.txt + * Copyright 2014 Edgar Espina + */ +package io.jooby.trpc.avaje.jsonb; + +import edu.umd.cs.findbugs.annotations.NonNull; +import io.avaje.json.JsonDataException; +import io.avaje.jsonb.Jsonb; +import io.jooby.Extension; +import io.jooby.Jooby; +import io.jooby.StatusCode; +import io.jooby.internal.trpc.avaje.jsonb.AvajeTrpcParser; +import io.jooby.trpc.TrpcErrorCode; +import io.jooby.trpc.TrpcParser; + +public class TrpcAvajeJsonbModule implements Extension { + @Override + public void install(@NonNull Jooby application) throws Exception { + var services = application.getServices(); + // tRpc + services.put(TrpcParser.class, new AvajeTrpcParser(application.require(Jsonb.class))); + application.errorCode(JsonDataException.class, StatusCode.BAD_REQUEST); + services + .mapOf(Class.class, TrpcErrorCode.class) + .put(JsonDataException.class, TrpcErrorCode.BAD_REQUEST); + } +} diff --git a/modules/jooby-trpc-avaje-jsonb/src/main/java/io/jooby/trpc/avaje/jsonb/TrpcJsonbExtension.java b/modules/jooby-trpc-avaje-jsonb/src/main/java/io/jooby/trpc/avaje/jsonb/TrpcJsonbExtension.java new file mode 100644 index 0000000000..c4946f9a42 --- /dev/null +++ b/modules/jooby-trpc-avaje-jsonb/src/main/java/io/jooby/trpc/avaje/jsonb/TrpcJsonbExtension.java @@ -0,0 +1,18 @@ +/* + * Jooby https://jooby.io + * Apache License Version 2.0 https://jooby.io/LICENSE.txt + * Copyright 2014 Edgar Espina + */ +package io.jooby.trpc.avaje.jsonb; + +import io.avaje.jsonb.Jsonb; +import io.avaje.jsonb.spi.JsonbComponent; +import io.jooby.internal.trpc.avaje.jsonb.AvajeTrpcResponseAdapter; +import io.jooby.trpc.TrpcResponse; + +public class TrpcJsonbExtension implements JsonbComponent { + @Override + public void register(Jsonb.Builder jsonb) { + jsonb.add(TrpcResponse.class, AvajeTrpcResponseAdapter::new); + } +} diff --git a/modules/jooby-trpc-avaje-jsonb/src/main/resources/META-INF/services/io.avaje.jsonb.spi.JsonbExtension b/modules/jooby-trpc-avaje-jsonb/src/main/resources/META-INF/services/io.avaje.jsonb.spi.JsonbExtension new file mode 100644 index 0000000000..2a14d4fd9c --- /dev/null +++ b/modules/jooby-trpc-avaje-jsonb/src/main/resources/META-INF/services/io.avaje.jsonb.spi.JsonbExtension @@ -0,0 +1 @@ +io.jooby.trpc.avaje.jsonb.TrpcJsonbExtension diff --git a/modules/jooby-trpc-generator/pom.xml b/modules/jooby-trpc-generator/pom.xml new file mode 100644 index 0000000000..4a3eab48f8 --- /dev/null +++ b/modules/jooby-trpc-generator/pom.xml @@ -0,0 +1,144 @@ + + + + 4.0.0 + + + io.jooby + modules + 4.2.1-SNAPSHOT + + jooby-trpc-generator + jooby-trpc-generator + + + + + + org.slf4j + slf4j-api + + + + io.github.classgraph + classgraph + 4.8.184 + + + + cz.habarta.typescript-generator + typescript-generator-core + 3.2.1263 + + + + + io.jooby + jooby-trpc + ${jooby.version} + test + + + + org.junit.jupiter + junit-jupiter-engine + test + + + + org.jacoco + org.jacoco.agent + runtime + test + + + + org.slf4j + slf4j-simple + ${slf4j.version} + test + + + + io.jooby + jooby-kotlin + ${jooby.version} + test + + + + org.jetbrains.kotlin + kotlin-stdlib + test + + + + org.jetbrains.kotlin + kotlin-reflect + test + + + + org.mockito + mockito-core + test + + + io.projectreactor + reactor-core + 3.8.4 + + + org.assertj + assertj-core + 3.27.7 + test + + + + + + + org.jetbrains.kotlin + kotlin-maven-plugin + + + compile + none + + + test-compile + + + ${project.basedir}/src/test/kotlin + ${project.basedir}/src/test/java + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + none + + + + default-testCompile + none + + + java-test-compile + + testCompile + + test-compile + + + + + + diff --git a/modules/jooby-trpc/src/main/java/io/jooby/trpc/TrpcGenerator.java b/modules/jooby-trpc-generator/src/main/java/io/jooby/trpc/TrpcGenerator.java similarity index 97% rename from modules/jooby-trpc/src/main/java/io/jooby/trpc/TrpcGenerator.java rename to modules/jooby-trpc-generator/src/main/java/io/jooby/trpc/TrpcGenerator.java index 0052180766..58cf325634 100644 --- a/modules/jooby-trpc/src/main/java/io/jooby/trpc/TrpcGenerator.java +++ b/modules/jooby-trpc-generator/src/main/java/io/jooby/trpc/TrpcGenerator.java @@ -363,11 +363,11 @@ private void appendProcedure(StringBuilder ts, String indent, Method method) { private boolean isMutation(Method method) { // 1. Explicit tRPC mutation annotation - if (getAnnotation(method, "io.jooby.annotation.Trpc$Mutation") != null) { + if (getAnnotation(method, "io.jooby.annotation.trpc.Trpc$Mutation") != null) { return true; } // 2. Explicit tRPC query annotation - if (getAnnotation(method, "io.jooby.annotation.Trpc$Query") != null) { + if (getAnnotation(method, "io.jooby.annotation.trpc.Trpc$Query") != null) { return false; } @@ -550,9 +550,9 @@ private Annotation getAnnotation(AnnotatedElement element, String annotationName * @return True if annotated with `@Trpc`, `@Trpc.Query`, or `@Trpc.Mutation`. */ private boolean isTrpcAnnotated(AnnotatedElement element) { - return getAnnotation(element, "io.jooby.annotation.Trpc") != null - || getAnnotation(element, "io.jooby.annotation.Trpc$Query") != null - || getAnnotation(element, "io.jooby.annotation.Trpc$Mutation") != null; + return getAnnotation(element, "io.jooby.annotation.trpc.Trpc") != null + || getAnnotation(element, "io.jooby.annotation.trpc.Trpc$Query") != null + || getAnnotation(element, "io.jooby.annotation.trpc.Trpc$Mutation") != null; } /** @@ -561,9 +561,9 @@ private boolean isTrpcAnnotated(AnnotatedElement element) { */ private String getProcedureName(Method method) { String[] procedureAnnotations = { - "io.jooby.annotation.Trpc$Query", - "io.jooby.annotation.Trpc$Mutation", - "io.jooby.annotation.Trpc" + "io.jooby.annotation.trpc.Trpc$Query", + "io.jooby.annotation.trpc.Trpc$Mutation", + "io.jooby.annotation.trpc.Trpc" }; for (String annName : procedureAnnotations) { @@ -591,7 +591,7 @@ private String getProcedureName(Method method) { * @return The determined namespace string, or null for root-level. */ private String extractNamespace(Class controller) { - Annotation trpc = getAnnotation(controller, "io.jooby.annotation.Trpc"); + Annotation trpc = getAnnotation(controller, "io.jooby.annotation.trpc.Trpc"); if (trpc != null) { try { var method = trpc.annotationType().getMethod("value"); diff --git a/modules/jooby-trpc/src/test/java/io/jooby/trpc/i3863/C3863.java b/modules/jooby-trpc-generator/src/test/java/io/jooby/trpc/i3863/C3863.java similarity index 95% rename from modules/jooby-trpc/src/test/java/io/jooby/trpc/i3863/C3863.java rename to modules/jooby-trpc-generator/src/test/java/io/jooby/trpc/i3863/C3863.java index 1c7347cfa2..0a97a2edb3 100644 --- a/modules/jooby-trpc/src/test/java/io/jooby/trpc/i3863/C3863.java +++ b/modules/jooby-trpc-generator/src/test/java/io/jooby/trpc/i3863/C3863.java @@ -9,6 +9,7 @@ import io.jooby.Context; import io.jooby.annotation.*; +import io.jooby.annotation.trpc.Trpc; import reactor.core.publisher.Mono; @Path("/users") diff --git a/modules/jooby-trpc/src/test/java/io/jooby/trpc/i3863/TrpcGeneratorTest.java b/modules/jooby-trpc-generator/src/test/java/io/jooby/trpc/i3863/TrpcGeneratorTest.java similarity index 100% rename from modules/jooby-trpc/src/test/java/io/jooby/trpc/i3863/TrpcGeneratorTest.java rename to modules/jooby-trpc-generator/src/test/java/io/jooby/trpc/i3863/TrpcGeneratorTest.java diff --git a/modules/jooby-trpc/src/test/java/io/jooby/trpc/i3863/U3863.java b/modules/jooby-trpc-generator/src/test/java/io/jooby/trpc/i3863/U3863.java similarity index 100% rename from modules/jooby-trpc/src/test/java/io/jooby/trpc/i3863/U3863.java rename to modules/jooby-trpc-generator/src/test/java/io/jooby/trpc/i3863/U3863.java diff --git a/modules/jooby-trpc-jackson2/pom.xml b/modules/jooby-trpc-jackson2/pom.xml new file mode 100644 index 0000000000..35c0a4ddc1 --- /dev/null +++ b/modules/jooby-trpc-jackson2/pom.xml @@ -0,0 +1,28 @@ + + + 4.0.0 + + io.jooby + modules + 4.2.1-SNAPSHOT + + + jooby-trpc-jackson2 + jooby-trpc-jackson2 + + + + io.jooby + jooby-trpc + ${jooby.version} + + + + com.fasterxml.jackson.core + jackson-databind + + + + diff --git a/modules/jooby-jackson/src/main/java/io/jooby/internal/jackson/JacksonTrpcDecoder.java b/modules/jooby-trpc-jackson2/src/main/java/io/jooby/internal/trpc/jackson2/JacksonTrpcDecoder.java similarity index 91% rename from modules/jooby-jackson/src/main/java/io/jooby/internal/jackson/JacksonTrpcDecoder.java rename to modules/jooby-trpc-jackson2/src/main/java/io/jooby/internal/trpc/jackson2/JacksonTrpcDecoder.java index 8cb2967ce3..3ff5cb2b8c 100644 --- a/modules/jooby-jackson/src/main/java/io/jooby/internal/jackson/JacksonTrpcDecoder.java +++ b/modules/jooby-trpc-jackson2/src/main/java/io/jooby/internal/trpc/jackson2/JacksonTrpcDecoder.java @@ -3,13 +3,13 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.internal.jackson; +package io.jooby.internal.trpc.jackson2; import java.io.IOException; import com.fasterxml.jackson.databind.ObjectReader; import io.jooby.SneakyThrows; -import io.jooby.rpc.trpc.TrpcDecoder; +import io.jooby.trpc.TrpcDecoder; public class JacksonTrpcDecoder implements TrpcDecoder { diff --git a/modules/jooby-jackson/src/main/java/io/jooby/internal/jackson/JacksonTrpcParser.java b/modules/jooby-trpc-jackson2/src/main/java/io/jooby/internal/trpc/jackson2/JacksonTrpcParser.java similarity index 89% rename from modules/jooby-jackson/src/main/java/io/jooby/internal/jackson/JacksonTrpcParser.java rename to modules/jooby-trpc-jackson2/src/main/java/io/jooby/internal/trpc/jackson2/JacksonTrpcParser.java index 7ed11e685b..38c975d7d6 100644 --- a/modules/jooby-jackson/src/main/java/io/jooby/internal/jackson/JacksonTrpcParser.java +++ b/modules/jooby-trpc-jackson2/src/main/java/io/jooby/internal/trpc/jackson2/JacksonTrpcParser.java @@ -3,7 +3,7 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.internal.jackson; +package io.jooby.internal.trpc.jackson2; import java.io.IOException; import java.lang.reflect.Type; @@ -11,9 +11,9 @@ import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import io.jooby.SneakyThrows; -import io.jooby.rpc.trpc.TrpcDecoder; -import io.jooby.rpc.trpc.TrpcParser; -import io.jooby.rpc.trpc.TrpcReader; +import io.jooby.trpc.TrpcDecoder; +import io.jooby.trpc.TrpcParser; +import io.jooby.trpc.TrpcReader; public class JacksonTrpcParser implements TrpcParser { diff --git a/modules/jooby-jackson/src/main/java/io/jooby/internal/jackson/JacksonTrpcReader.java b/modules/jooby-trpc-jackson2/src/main/java/io/jooby/internal/trpc/jackson2/JacksonTrpcReader.java similarity index 96% rename from modules/jooby-jackson/src/main/java/io/jooby/internal/jackson/JacksonTrpcReader.java rename to modules/jooby-trpc-jackson2/src/main/java/io/jooby/internal/trpc/jackson2/JacksonTrpcReader.java index e316dada21..a05786c74d 100644 --- a/modules/jooby-jackson/src/main/java/io/jooby/internal/jackson/JacksonTrpcReader.java +++ b/modules/jooby-trpc-jackson2/src/main/java/io/jooby/internal/trpc/jackson2/JacksonTrpcReader.java @@ -3,7 +3,7 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.internal.jackson; +package io.jooby.internal.trpc.jackson2; import java.io.IOException; @@ -11,8 +11,8 @@ import com.fasterxml.jackson.core.JsonToken; import io.jooby.SneakyThrows; import io.jooby.exception.MissingValueException; -import io.jooby.rpc.trpc.TrpcDecoder; -import io.jooby.rpc.trpc.TrpcReader; +import io.jooby.trpc.TrpcDecoder; +import io.jooby.trpc.TrpcReader; public class JacksonTrpcReader implements TrpcReader { private final JsonParser parser; diff --git a/modules/jooby-jackson/src/main/java/io/jooby/internal/jackson/JacksonTrpcResponseSerializer.java b/modules/jooby-trpc-jackson2/src/main/java/io/jooby/internal/trpc/jackson2/JacksonTrpcResponseSerializer.java similarity index 85% rename from modules/jooby-jackson/src/main/java/io/jooby/internal/jackson/JacksonTrpcResponseSerializer.java rename to modules/jooby-trpc-jackson2/src/main/java/io/jooby/internal/trpc/jackson2/JacksonTrpcResponseSerializer.java index 68e939da8b..90ecdff8a1 100644 --- a/modules/jooby-jackson/src/main/java/io/jooby/internal/jackson/JacksonTrpcResponseSerializer.java +++ b/modules/jooby-trpc-jackson2/src/main/java/io/jooby/internal/trpc/jackson2/JacksonTrpcResponseSerializer.java @@ -3,14 +3,14 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.internal.jackson; +package io.jooby.internal.trpc.jackson2; import java.io.IOException; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.ser.std.StdSerializer; -import io.jooby.rpc.trpc.TrpcResponse; +import io.jooby.trpc.TrpcResponse; public class JacksonTrpcResponseSerializer extends StdSerializer { public JacksonTrpcResponseSerializer() { @@ -20,10 +20,10 @@ public JacksonTrpcResponseSerializer() { @Override public void serialize(TrpcResponse value, JsonGenerator gen, SerializerProvider provider) throws IOException { - gen.writeStartObject(); // { + gen.writeStartObject(); gen.writeFieldName("result"); - gen.writeStartObject(); // "result": { + gen.writeStartObject(); var data = value.data(); // Only write the "data" key if the method actually returned something (not void/Unit) diff --git a/modules/jooby-trpc-jackson2/src/main/java/io/jooby/trpc/jackson2/TrpcJackson2Module.java b/modules/jooby-trpc-jackson2/src/main/java/io/jooby/trpc/jackson2/TrpcJackson2Module.java new file mode 100644 index 0000000000..f7932feed1 --- /dev/null +++ b/modules/jooby-trpc-jackson2/src/main/java/io/jooby/trpc/jackson2/TrpcJackson2Module.java @@ -0,0 +1,28 @@ +/* + * Jooby https://jooby.io + * Apache License Version 2.0 https://jooby.io/LICENSE.txt + * Copyright 2014 Edgar Espina + */ +package io.jooby.trpc.jackson2; + +import com.fasterxml.jackson.databind.Module; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; +import edu.umd.cs.findbugs.annotations.NonNull; +import io.jooby.Extension; +import io.jooby.Jooby; +import io.jooby.internal.trpc.jackson2.JacksonTrpcParser; +import io.jooby.internal.trpc.jackson2.JacksonTrpcResponseSerializer; +import io.jooby.trpc.TrpcParser; +import io.jooby.trpc.TrpcResponse; + +public class TrpcJackson2Module implements Extension { + @Override + public void install(@NonNull Jooby application) throws Exception { + var services = application.getServices(); + services.put(TrpcParser.class, new JacksonTrpcParser(application.require(ObjectMapper.class))); + var rpc = new SimpleModule(); + rpc.addSerializer(TrpcResponse.class, new JacksonTrpcResponseSerializer()); + services.listOf(Module.class).add(rpc); + } +} diff --git a/modules/jooby-trpc-jackson2/src/main/java/module-info.java b/modules/jooby-trpc-jackson2/src/main/java/module-info.java new file mode 100644 index 0000000000..6b0a463005 --- /dev/null +++ b/modules/jooby-trpc-jackson2/src/main/java/module-info.java @@ -0,0 +1,9 @@ +module io.jooby.trpc.jackson2 { + exports io.jooby.trpc.jackson2; + + requires io.jooby; + requires io.jooby.trpc; + requires static com.github.spotbugs.annotations; + requires typesafe.config; + requires com.fasterxml.jackson.databind; +} diff --git a/modules/jooby-trpc-jackson3/pom.xml b/modules/jooby-trpc-jackson3/pom.xml new file mode 100644 index 0000000000..eed1c49436 --- /dev/null +++ b/modules/jooby-trpc-jackson3/pom.xml @@ -0,0 +1,29 @@ + + + 4.0.0 + + io.jooby + modules + 4.2.1-SNAPSHOT + + + jooby-trpc-jackson3 + jooby-trpc-jackson3 + + + + io.jooby + jooby-trpc + ${jooby.version} + + + + + tools.jackson.core + jackson-databind + + + + diff --git a/modules/jooby-jackson3/src/main/java/io/jooby/internal/jackson3/JacksonTrpcDecoder.java b/modules/jooby-trpc-jackson3/src/main/java/io/jooby/internal/trpc/jackson3/JacksonTrpcDecoder.java similarity index 88% rename from modules/jooby-jackson3/src/main/java/io/jooby/internal/jackson3/JacksonTrpcDecoder.java rename to modules/jooby-trpc-jackson3/src/main/java/io/jooby/internal/trpc/jackson3/JacksonTrpcDecoder.java index a1d3b84210..7203b40d90 100644 --- a/modules/jooby-jackson3/src/main/java/io/jooby/internal/jackson3/JacksonTrpcDecoder.java +++ b/modules/jooby-trpc-jackson3/src/main/java/io/jooby/internal/trpc/jackson3/JacksonTrpcDecoder.java @@ -3,9 +3,9 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.internal.jackson3; +package io.jooby.internal.trpc.jackson3; -import io.jooby.rpc.trpc.TrpcDecoder; +import io.jooby.trpc.TrpcDecoder; import tools.jackson.databind.ObjectReader; public class JacksonTrpcDecoder implements TrpcDecoder { diff --git a/modules/jooby-jackson3/src/main/java/io/jooby/internal/jackson3/JacksonTrpcParser.java b/modules/jooby-trpc-jackson3/src/main/java/io/jooby/internal/trpc/jackson3/JacksonTrpcParser.java similarity index 81% rename from modules/jooby-jackson3/src/main/java/io/jooby/internal/jackson3/JacksonTrpcParser.java rename to modules/jooby-trpc-jackson3/src/main/java/io/jooby/internal/trpc/jackson3/JacksonTrpcParser.java index c85ef8d977..b922257339 100644 --- a/modules/jooby-jackson3/src/main/java/io/jooby/internal/jackson3/JacksonTrpcParser.java +++ b/modules/jooby-trpc-jackson3/src/main/java/io/jooby/internal/trpc/jackson3/JacksonTrpcParser.java @@ -3,21 +3,23 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.internal.jackson3; +package io.jooby.internal.trpc.jackson3; import java.lang.reflect.Type; -import io.jooby.rpc.trpc.TrpcDecoder; -import io.jooby.rpc.trpc.TrpcParser; -import io.jooby.rpc.trpc.TrpcReader; +import io.jooby.trpc.TrpcDecoder; +import io.jooby.trpc.TrpcParser; +import io.jooby.trpc.TrpcReader; import tools.jackson.databind.DeserializationFeature; import tools.jackson.databind.ObjectMapper; public class JacksonTrpcParser implements TrpcParser { - private final ObjectMapper mapper; + private ObjectMapper mapper; - public JacksonTrpcParser(ObjectMapper mapper) { + public JacksonTrpcParser() {} + + public void setMapper(ObjectMapper mapper) { this.mapper = mapper; } diff --git a/modules/jooby-jackson3/src/main/java/io/jooby/internal/jackson3/JacksonTrpcReader.java b/modules/jooby-trpc-jackson3/src/main/java/io/jooby/internal/trpc/jackson3/JacksonTrpcReader.java similarity index 91% rename from modules/jooby-jackson3/src/main/java/io/jooby/internal/jackson3/JacksonTrpcReader.java rename to modules/jooby-trpc-jackson3/src/main/java/io/jooby/internal/trpc/jackson3/JacksonTrpcReader.java index 29d285876d..4797db84bf 100644 --- a/modules/jooby-jackson3/src/main/java/io/jooby/internal/jackson3/JacksonTrpcReader.java +++ b/modules/jooby-trpc-jackson3/src/main/java/io/jooby/internal/trpc/jackson3/JacksonTrpcReader.java @@ -3,11 +3,11 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.internal.jackson3; +package io.jooby.internal.trpc.jackson3; import io.jooby.exception.MissingValueException; -import io.jooby.rpc.trpc.TrpcDecoder; -import io.jooby.rpc.trpc.TrpcReader; +import io.jooby.trpc.TrpcDecoder; +import io.jooby.trpc.TrpcReader; import tools.jackson.core.JsonParser; import tools.jackson.core.JsonToken; @@ -21,7 +21,7 @@ public JacksonTrpcReader(JsonParser parser, boolean isTuple) { this.parser = parser; this.isTuple = isTuple; var token = parser.nextToken(); - if (isTuple && token != tools.jackson.core.JsonToken.START_ARRAY) { + if (isTuple && token != JsonToken.START_ARRAY) { throw new IllegalArgumentException("Expected tRPC tuple array"); } } @@ -63,7 +63,7 @@ private void advance(String name) { } var token = parser.nextToken(); - if (token == tools.jackson.core.JsonToken.END_ARRAY || token == null) { + if (token == JsonToken.END_ARRAY || token == null) { throw new MissingValueException(name); } } diff --git a/modules/jooby-jackson3/src/main/java/io/jooby/internal/jackson3/JacksonTrpcResponseSerializer.java b/modules/jooby-trpc-jackson3/src/main/java/io/jooby/internal/trpc/jackson3/JacksonTrpcResponseSerializer.java similarity index 92% rename from modules/jooby-jackson3/src/main/java/io/jooby/internal/jackson3/JacksonTrpcResponseSerializer.java rename to modules/jooby-trpc-jackson3/src/main/java/io/jooby/internal/trpc/jackson3/JacksonTrpcResponseSerializer.java index 2676d1607c..0245ec4c3e 100644 --- a/modules/jooby-jackson3/src/main/java/io/jooby/internal/jackson3/JacksonTrpcResponseSerializer.java +++ b/modules/jooby-trpc-jackson3/src/main/java/io/jooby/internal/trpc/jackson3/JacksonTrpcResponseSerializer.java @@ -3,9 +3,9 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.internal.jackson3; +package io.jooby.internal.trpc.jackson3; -import io.jooby.rpc.trpc.TrpcResponse; +import io.jooby.trpc.TrpcResponse; import tools.jackson.core.JacksonException; import tools.jackson.core.JsonGenerator; import tools.jackson.databind.SerializationContext; diff --git a/modules/jooby-trpc-jackson3/src/main/java/io/jooby/trpc/jackson3/TrpcJackson3Module.java b/modules/jooby-trpc-jackson3/src/main/java/io/jooby/trpc/jackson3/TrpcJackson3Module.java new file mode 100644 index 0000000000..10f3ca0664 --- /dev/null +++ b/modules/jooby-trpc-jackson3/src/main/java/io/jooby/trpc/jackson3/TrpcJackson3Module.java @@ -0,0 +1,41 @@ +/* + * Jooby https://jooby.io + * Apache License Version 2.0 https://jooby.io/LICENSE.txt + * Copyright 2014 Edgar Espina + */ +package io.jooby.trpc.jackson3; + +import edu.umd.cs.findbugs.annotations.NonNull; +import io.jooby.Extension; +import io.jooby.Jooby; +import io.jooby.internal.trpc.jackson3.JacksonTrpcParser; +import io.jooby.internal.trpc.jackson3.JacksonTrpcResponseSerializer; +import io.jooby.trpc.TrpcErrorCode; +import io.jooby.trpc.TrpcParser; +import io.jooby.trpc.TrpcResponse; +import tools.jackson.core.exc.StreamReadException; +import tools.jackson.databind.DatabindException; +import tools.jackson.databind.JacksonModule; +import tools.jackson.databind.ObjectMapper; +import tools.jackson.databind.exc.MismatchedInputException; +import tools.jackson.databind.module.SimpleModule; + +public class TrpcJackson3Module implements Extension { + @Override + public void install(@NonNull Jooby application) { + var services = application.getServices(); + // tRPC error codes + services + .mapOf(Class.class, TrpcErrorCode.class) + .put(StreamReadException.class, TrpcErrorCode.BAD_REQUEST) + .put(MismatchedInputException.class, TrpcErrorCode.BAD_REQUEST) + .put(DatabindException.class, TrpcErrorCode.BAD_REQUEST); + var trpcParser = new JacksonTrpcParser(); + services.put(TrpcParser.class, trpcParser); + var rpc = new SimpleModule(); + rpc.addSerializer(TrpcResponse.class, new JacksonTrpcResponseSerializer()); + services.listOf(JacksonModule.class).add(rpc); + // bind to final mapper + application.onStarting(() -> trpcParser.setMapper(application.require(ObjectMapper.class))); + } +} diff --git a/modules/jooby-trpc-jackson3/src/main/java/module-info.java b/modules/jooby-trpc-jackson3/src/main/java/module-info.java new file mode 100644 index 0000000000..5ea0344e80 --- /dev/null +++ b/modules/jooby-trpc-jackson3/src/main/java/module-info.java @@ -0,0 +1,10 @@ +module io.jooby.trpc.jackson3 { + exports io.jooby.trpc.jackson3; + + requires io.jooby; + requires io.jooby.trpc; + requires static com.github.spotbugs.annotations; + requires typesafe.config; + requires tools.jackson.core; + requires tools.jackson.databind; +} diff --git a/modules/jooby-trpc/pom.xml b/modules/jooby-trpc/pom.xml index 1bc72cc53c..d1c6e27db8 100644 --- a/modules/jooby-trpc/pom.xml +++ b/modules/jooby-trpc/pom.xml @@ -24,18 +24,6 @@ jakarta.ws.rs-api - - io.github.classgraph - classgraph - 4.8.184 - - - - cz.habarta.typescript-generator - typescript-generator-core - 3.2.1263 - - org.junit.jupiter diff --git a/jooby/src/main/java/io/jooby/annotation/Trpc.java b/modules/jooby-trpc/src/main/java/io/jooby/annotation/trpc/Trpc.java similarity index 88% rename from jooby/src/main/java/io/jooby/annotation/Trpc.java rename to modules/jooby-trpc/src/main/java/io/jooby/annotation/trpc/Trpc.java index a3988077ff..f705c4f9e9 100644 --- a/jooby/src/main/java/io/jooby/annotation/Trpc.java +++ b/modules/jooby-trpc/src/main/java/io/jooby/annotation/trpc/Trpc.java @@ -3,13 +3,9 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.annotation; +package io.jooby.annotation.trpc; -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; +import java.lang.annotation.*; /** * Marks a controller class or a specific route method for tRPC TypeScript generation. @@ -23,8 +19,8 @@ *

There are two ways to expose a method as a tRPC procedure: * *