diff --git a/.github/workflows/full-build.yml b/.github/workflows/full-build.yml index 1bae712752..31c1ec5791 100644 --- a/.github/workflows/full-build.yml +++ b/.github/workflows/full-build.yml @@ -1,6 +1,12 @@ name: Full Build -on: [push] +on: + push: + branches: + - main # Only run push on main (merges/direct pushes) + pull_request: + branches: + - main # Run on any PR targeting main jobs: build: diff --git a/docs/asciidoc/modules/avaje-jsonb.adoc b/docs/asciidoc/modules/avaje-jsonb.adoc index 345c1f45ab..2898470994 100644 --- a/docs/asciidoc/modules/avaje-jsonb.adoc +++ b/docs/asciidoc/modules/avaje-jsonb.adoc @@ -81,7 +81,7 @@ import io.jooby.avaje.jsonb.AvajeJsonbModule import io.avaje.jsonb.Jsonb { - install(JacksonModule()) + install(AvajeJsonbModule()) val jsonb = require() } diff --git a/docs/asciidoc/gRPC.adoc b/docs/asciidoc/modules/gRPC.adoc similarity index 73% rename from docs/asciidoc/gRPC.adoc rename to docs/asciidoc/modules/gRPC.adoc index 3e5a1471da..e96a4aeedf 100644 --- a/docs/asciidoc/gRPC.adoc +++ b/docs/asciidoc/modules/gRPC.adoc @@ -1,4 +1,4 @@ -==== gRPC +== gRPC The `jooby-grpc` module provides first-class, native support for https://grpc.io/[gRPC]. @@ -6,25 +6,12 @@ Unlike traditional setups that require spinning up a separate gRPC server on a d By using a custom native bridge, it allows you to run strictly-typed gRPC services alongside your standard REST API routes on the **exact same port**. It bypasses the standard HTTP/1.1 pipeline in favor of a highly optimized, native interceptor tailored for HTTP/2 multiplexing, reactive backpressure, and zero-copy byte framing. It works natively across Undertow, Netty, and Jetty. -===== Usage +=== Usage gRPC strictly requires HTTP/2. Before installing the module, ensure your application is configured to use a supported server with HTTP/2 enabled. -[source, xml, role="primary"] -.Maven ----- - - io.jooby - jooby-grpc - ${jooby.version} - ----- - -[source, gradle, role="secondary"] -.Gradle ----- -implementation 'io.jooby:jooby-grpc:${jooby.version}' ----- +[dependency, artifactId="jooby-grpc"] +. [source, java, role="primary"] .Java @@ -33,16 +20,10 @@ import io.jooby.Jooby; import io.jooby.ServerOptions; import io.jooby.grpc.GrpcModule; -public class App extends Jooby { - { - setServerOptions(new ServerOptions().setHttp2(true)); // <1> - - install(new GrpcModule( // <2> - new GreeterService() - )); +{ + setServerOptions(new ServerOptions().setHttp2(true)); // <1> - get("/api/health", ctx -> "OK"); // <3> - } + install(new GrpcModule(new GreeterService())); // <2> } ---- @@ -53,22 +34,17 @@ import io.jooby.ServerOptions import io.jooby.grpc.GrpcModule import io.jooby.kt.Kooby -class App : Kooby({ - serverOptions = ServerOptions().setHttp2(true) // <1> - - install(GrpcModule( // <2> - GreeterService() - )) +{ + serverOptions = ServerOptions().setHttp2(true) // <1> - get("/api/health") { "OK" } // <3> -}) + install(GrpcModule(GreeterService())) // <2> +} ---- <1> Enable HTTP/2 on your server. <2> Install the module and explicitly register your services. -<3> Standard REST routes still work on the exact same port! -===== Dependency Injection +=== Dependency Injection If your gRPC services require external dependencies (like database repositories), you can register the service classes instead of pre-instantiated objects. The module will automatically provision them using your active Dependency Injection framework (e.g., Guice, Spring). @@ -79,14 +55,10 @@ import io.jooby.Jooby; import io.jooby.di.GuiceModule; import io.jooby.grpc.GrpcModule; -public class App extends Jooby { - { - install(new GuiceModule()); +{ + install(new GuiceModule()); - install(new GrpcModule( - GreeterService.class // <1> - )); - } + install(new GrpcModule(GreeterService.class)); // <1> } ---- @@ -97,19 +69,17 @@ import io.jooby.di.GuiceModule import io.jooby.grpc.GrpcModule import io.jooby.kt.Kooby -class App : Kooby({ +{ install(GuiceModule()) - install(GrpcModule( - GreeterService::class.java // <1> - )) -}) + install(GrpcModule(GreeterService::class.java)) // <1> +} ---- <1> Pass the class references. The DI framework will instantiate them. WARNING: gRPC services are registered as **Singletons**. Ensure your service implementations are thread-safe and do not hold request-scoped state in instance variables. Heavy blocking operations will safely run on background workers, protecting the native server's I/O event loops. -===== Server Reflection +=== Server Reflection If you want to use tools like `grpcurl` or Postman to interact with your services without providing the `.proto` files, you can easily enable gRPC Server Reflection. @@ -122,13 +92,11 @@ import io.grpc.protobuf.services.ProtoReflectionServiceV1; import io.jooby.Jooby; import io.jooby.grpc.GrpcModule; -public class App extends Jooby { - { - install(new GrpcModule( - new GreeterService(), - ProtoReflectionServiceV1.newInstance() // <1> - )); - } +{ + install(new GrpcModule( + new GreeterService(), + ProtoReflectionServiceV1.newInstance() // <1> + )); } ---- @@ -139,16 +107,16 @@ import io.grpc.protobuf.services.ProtoReflectionServiceV1 import io.jooby.grpc.GrpcModule import io.jooby.kt.Kooby -class App : Kooby({ +{ install(GrpcModule( GreeterService(), ProtoReflectionServiceV1.newInstance() // <1> )) -}) +} ---- <1> Enables the modern `v1` reflection protocol for maximum compatibility with gRPC clients. -===== Routing & Fallbacks +=== Routing & Fallbacks The gRPC module intercepts requests natively before they reach Jooby's standard router. diff --git a/docs/asciidoc/modules/graphql.adoc b/docs/asciidoc/modules/graphql.adoc index 3d0fcc8f2b..a9dc781166 100644 --- a/docs/asciidoc/modules/graphql.adoc +++ b/docs/asciidoc/modules/graphql.adoc @@ -36,11 +36,11 @@ type Author { .Java [source, java, role="primary"] ---- -import io.jooby.json.JacksonModule; +import io.jooby.json.Jackson2Module; import io.jooby.graphql.GraphQLModule; { - install(new JacksonModule()); <1> + install(new Jackson2Module()); <1> install(new GraphQLModule( RuntimeWiring.newRuntimeWiring() <2> @@ -56,11 +56,11 @@ import io.jooby.graphql.GraphQLModule; .Kotlin [source, kt, role="secondary"] ---- -import io.jooby.json.JacksonModule +import io.jooby.json.Jackson2Module import io.jooby.graphql.GraphQLModule { - install(JacksonModule()) <1> + install(Jackson2Module()) <1> install(GraphQLModule( RuntimeWiring.newRuntimeWiring() <2> @@ -88,7 +88,7 @@ the async mode: .Async Mode [source, java, role="primary"] ---- -import io.jooby.json.JacksonModule; +import io.jooby.json.Jackson2Module; import io.jooby.graphql.GraphQLModule; { @@ -101,7 +101,7 @@ import io.jooby.graphql.GraphQLModule; .Kotlin [source, kt, role="secondary"] ---- -import io.jooby.json.JacksonModule +import io.jooby.json.Jackson2Module import io.jooby.graphql.GraphQLModule { @@ -122,7 +122,7 @@ By default the module only install a HTTP POST route. If you want a HTTP GET: .HTTP GET [source, java, role="primary"] ---- -import io.jooby.json.JacksonModule; +import io.jooby.json.Jackson2Module; import io.jooby.graphql.GraphQLModule; { @@ -135,7 +135,7 @@ import io.jooby.graphql.GraphQLModule; .Kotlin [source, kt, role="secondary"] ---- -import io.jooby.json.JacksonModule +import io.jooby.json.Jackson2Module import io.jooby.graphql.GraphQLModule { @@ -170,12 +170,12 @@ They are provided as optional dependencies. .Java [source, java, role="primary"] ---- -import io.jooby.json.JacksonModule; +import io.jooby.json.Jackson2Module; import io.jooby.graphql.GraphQLModule; import io.jooby.graphql.GraphiQLModule; { - install(new JacksonModule()); <1> + install(new Jackson2Module()); <1> install(new GraphQLModule(...)); <2> @@ -186,12 +186,12 @@ import io.jooby.graphql.GraphiQLModule; .Kotlin [source, kt, role="secondary"] ---- -import io.jooby.json.JacksonModule +import io.jooby.json.Jackson2Module import io.jooby.graphql.GraphQLModule import io.jooby.graphql.GraphiQLModule { - install(JacksonModule()) <1> + install(Jackson2Module()) <1> install(GraphQLModule(...)) <2> @@ -217,12 +217,12 @@ https://github.com/graphql/graphiql[GraphiQL] should be up and running at `/grap .Java [source, java, role="primary"] ---- -import io.jooby.json.JacksonModule; +import io.jooby.json.Jackson2Module; import io.jooby.graphql.GraphQLModule; import io.jooby.graphql.GraphQLPlaygroundModule; { - install(new JacksonModule()); <1> + install(new Jackson2Module()); <1> install(new GraphQLModule(...)); <2> @@ -233,12 +233,12 @@ import io.jooby.graphql.GraphQLPlaygroundModule; .Kotlin [source, kt, role="secondary"] ---- -import io.jooby.json.JacksonModule +import io.jooby.json.Jackson2Module import io.jooby.graphql.GraphQLModule import io.jooby.graphql.GraphQLPlaygroundModule { - install(JacksonModule()) <1> + install(Jackson2Module()) <1> install(GraphQLModule(...)) <2> diff --git a/docs/asciidoc/modules/hibernate-validator.adoc b/docs/asciidoc/modules/hibernate-validator.adoc index c4cb738e17..4c1e6839d2 100644 --- a/docs/asciidoc/modules/hibernate-validator.adoc +++ b/docs/asciidoc/modules/hibernate-validator.adoc @@ -191,7 +191,7 @@ It is possible to override the `title` and `status` code of the response above: ---- { - install(new JacksonModule()); + install(new Jackson2Module()); install(new HibernateValidatorModule() .statusCode(StatusCode.BAD_REQUEST) .validationTitle("Incorrect input data") @@ -205,7 +205,7 @@ If the default error handler doesn't fully meet your needs, you can always disab ---- { - install(new JacksonModule()); + install(new Jackson2Module()); install(new HibernateValidatorModule().disableViolationHandler()); error(ConstraintViolationException.class, new MyConstraintViolationHandler()); diff --git a/docs/asciidoc/modules/jackson2.adoc b/docs/asciidoc/modules/jackson2.adoc index efcfb70c77..0d6fbf44ab 100644 --- a/docs/asciidoc/modules/jackson2.adoc +++ b/docs/asciidoc/modules/jackson2.adoc @@ -14,10 +14,10 @@ JSON support using https://github.com/FasterXML/jackson[Jackson 2] library. .Java [source, java, role="primary"] ---- -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; { - install(new JacksonModule()); <1> + install(new Jackson2Module()); <1> get("/", ctx -> { MyObject myObject = ...; @@ -34,10 +34,10 @@ import io.jooby.jackson.JacksonModule; .Kotlin [source, kt, role="secondary"] ---- -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; { - install(JacksonModule()) <1> + install(Jackson2Module()) <1> get("/") { val myObject = ...; @@ -62,10 +62,10 @@ Access to default object mapper is available via require call: .Default object mapper [source, java, role="primary"] ---- -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; { - install(new JacksonModule()); + install(new Jackson2Module()); ObjectMapper mapper = require(ObjectMapper.class); @@ -76,10 +76,10 @@ import io.jooby.jackson.JacksonModule; .Kotlin [source, kt, role="secondary"] ---- -import io.jooby.jackson.JacksonModule +import io.jooby.jackson.Jackson2Module { - install(JacksonModule()) + install(Jackson2Module()) val mapper = require() } @@ -90,46 +90,46 @@ You can provide your own `ObjectMapper`: .Custom ObjectMapper [source, java, role="primary"] ---- -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; { ObjectMapper mapper = new ObjectMapper(); - install(new JacksonModule(mapper)); + install(new Jackson2Module(mapper)); } ---- .Kotlin [source, kt, role="secondary"] ---- -import io.jooby.jackson.JacksonModule +import io.jooby.jackson.Jackson2Module { val mapper = ObjectMapper() - install(JacksonModule(mapper)) + install(Jackson2Module(mapper)) } ---- -This allows to configure JacksonModule for doing `xml` processing: +This allows to configure Jackson2Module for doing `xml` processing: .XmlMapper [source, java, role="primary"] ---- -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; { - install(new JacksonModule(new XmlMapper())); + install(new Jackson2Module(new XmlMapper())); } ---- .Kotlin [source, kt, role="secondary"] ---- -import io.jooby.jackson.JacksonModule +import io.jooby.jackson.Jackson2Module { - install(JacksonModule(XmlMapper())) + install(Jackson2Module(XmlMapper())) } ---- @@ -138,22 +138,22 @@ If you want `json` and `xml` processing then install twice: .XmlMapper [source, java, role="primary"] ---- -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; { - install(new JacksonModule(new ObjectMapper())); - install(new JacksonModule(new XmlMapper())); + install(new Jackson2Module(new ObjectMapper())); + install(new Jackson2Module(new XmlMapper())); } ---- .Kotlin [source, kt, role="secondary"] ---- -import io.jooby.jackson.JacksonModule +import io.jooby.jackson.Jackson2Module { - install(JacksonModule(ObjectMapper())) - install(JacksonModule(XmlMapper())) + install(Jackson2Module(ObjectMapper())) + install(Jackson2Module(XmlMapper())) } ---- @@ -164,20 +164,20 @@ Jackson module can be provided by a link:{uiVersion}/#ecosystem-services-and-the .Provisioning Modules [source, java, role="primary"] ---- -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; { - install(new JacksonModule().module(MyModule.class); + install(new Jackson2Module().module(MyModule.class); } ---- .Kotlin [source, kt, role="secondary"] ---- -import io.jooby.jackson.JacksonModule +import io.jooby.jackson.Jackson2Module { - install(JacksonModule().module(MyModule::class.java) + install(Jackson2Module().module(MyModule::class.java) } ---- diff --git a/docs/asciidoc/json-rpc.adoc b/docs/asciidoc/modules/json-rpc.adoc similarity index 82% rename from docs/asciidoc/json-rpc.adoc rename to docs/asciidoc/modules/json-rpc.adoc index c885afd392..0dcf695c8a 100644 --- a/docs/asciidoc/json-rpc.adoc +++ b/docs/asciidoc/modules/json-rpc.adoc @@ -1,10 +1,15 @@ -==== JSON-RPC +== JSON-RPC Jooby provides full support for the JSON-RPC 2.0 specification, allowing you to build robust RPC APIs using standard Java and Kotlin controllers. The implementation leverages Jooby's Annotation Processing Tool (APT) to generate highly optimized, reflection-free dispatchers at compile time. -===== Usage +=== Usage + +Add dependencies: + +[dependency, artifactId="jooby-jackson3:Jackson module, jooby-jsonrpc-jackson3:Jackson JSON-RPC implementation, jooby-jsonrpc:JSON-RPC Module"] +. To expose a JSON-RPC endpoint, annotate your controller or service with `@JsonRpc`. You can optionally provide a namespace to the annotation, which will prefix all generated method names for that class. @@ -50,7 +55,7 @@ The annotation dictates how the protocol methods are named and exposed: **Mixing Annotations:** You can freely mix standard REST annotations (like `@GET`, `@POST`) and `@JsonRpc` on the same class. The APT handles this by generating two entirely separate dispatchers: one standard MVC extension (e.g., `MovieService_`) and one JSON-RPC service (e.g., `MovieServiceRpc_`). They do not interfere with each other, allowing you to expose the exact same business logic over both REST and JSON-RPC simultaneously. -===== Registration +=== Registration Register the generated `JsonRpcService` in your application using the `jsonrpc` method. You must also install a supported JSON engine. @@ -58,17 +63,14 @@ Register the generated `JsonRpcService` in your application using the `jsonrpc` [source,java,role="primary"] ---- import io.jooby.Jooby; -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson3Module; -public class App extends Jooby { - { - install(new JacksonModule()); // <1> +{ + install(new Jackson3Module()); // <1> - jsonrpc(new MovieServiceRpc_()); // <2> + install(new JsonRpcJackson3Module()); // <2> - // Alternatively, you can override the default path: - // jsonrpc("/json-rpc", new MovieServiceRpc_()); - } + install(new JsonRpcModule(new MovieServiceRpc_())); // <3> } ---- @@ -76,35 +78,34 @@ public class App extends Jooby { [source,kotlin,role="secondary"] ---- import io.jooby.kt.Kooby -import io.jooby.jackson.JacksonModule +import io.jooby.jackson.Jackson3Module -class App : Kooby({ - - install(JacksonModule()) // <1> +{ + install(Jackson3Module()) // <1> - jsonrpc(MovieServiceRpc_()) // <2> + install(JsonRpcJackson3Module()) // <2> - // Custom endpoint: - // jsonrpc("/json-rpc", MovieServiceRpc_()) -}) + install(JsonRpcModule(MovieServiceRpc_())) // <3> +} ---- 1. Install a JSON engine -2. Register the generated JSON-RPC service +2. Install a JSON-RPC implementation +3. Register the generated JSON-RPC service -===== JSON Engine Support +=== JSON Engine Support The JSON-RPC extension delegates payload parsing and serialization to Jooby's standard JSON modules while enforcing strict JSON-RPC 2.0 compliance (such as the mutual exclusivity of `result` and `error` fields). Supported engines include: -* **Jackson 2** (`JacksonModule`) -* **Jackson 3** (`Jackson3Module`) -* **Avaje JSON-B** (`AvajeJsonbModule`) +* **Jackson 2**: `Jackson2Module`, `JsonRpcJackson2Module` +* **Jackson 3**: `Jackson3Module`, `JsonRpcJackson3Module` +* **Avaje JSON-B**: `AvajeJsonbModule`, `JsonRpcAvajeJsonbModule` No additional configuration is required. The generated dispatcher automatically hooks into the installed engine using the `JsonRpcParser` and `JsonRpcDecoder` interfaces, ensuring primitive types are strictly validated and parsed. -===== Error Mapping +=== Error Mapping Jooby seamlessly bridges standard Java application exceptions and HTTP status codes into the JSON-RPC 2.0 format using the `JsonRpcErrorCode` mapping. You do not need to throw custom protocol exceptions for standard failures. @@ -123,7 +124,7 @@ When an application exception is thrown (like a `NotFoundException` with an HTTP } ---- -====== Standard Protocol Errors +==== Standard Protocol Errors The engine handles core JSON-RPC 2.0 protocol errors automatically, returning HTTP 200 OK with the corresponding error payload: @@ -135,7 +136,7 @@ The engine handles core JSON-RPC 2.0 protocol errors automatically, returning HT Application-defined errors map standard HTTP status codes to the `-32000` to `-32099` range (e.g., an HTTP 404 maps to `-32004`, an HTTP 401 maps to `-32001`). -===== Batch Processing +=== Batch Processing Batch processing is natively supported. Clients can send an array of JSON-RPC request objects, and the dispatcher will process them and return an array of corresponding response objects. diff --git a/docs/asciidoc/modules/mcp.adoc b/docs/asciidoc/modules/mcp.adoc index a193f1705c..d63589193a 100644 --- a/docs/asciidoc/modules/mcp.adoc +++ b/docs/asciidoc/modules/mcp.adoc @@ -80,7 +80,7 @@ import io.jooby.mcp.McpModule } ---- -<1> Install JSON support (Jackson is required for MCP JSON-RPC serialization). For Jackson 2, use `JacksonModule()` instead. +<1> Install JSON support (Jackson is required for MCP JSON-RPC serialization). For Jackson 2, use `Jackson2Module()` instead. <2> Install MCP JSON support. For Jackson 2, use `McpJackson2Module()` instead. <3> Install the MCP module with the APT-generated `McpService` dispatcher. The generated class always ends with the `Mcp_` suffix. diff --git a/docs/asciidoc/modules/modules.adoc b/docs/asciidoc/modules/modules.adoc index e9c396b73b..ba9e6ab9fe 100644 --- a/docs/asciidoc/modules/modules.adoc +++ b/docs/asciidoc/modules/modules.adoc @@ -62,6 +62,11 @@ Modules are distributed as separate dependencies. Below is the catalog of offici * link:{uiVersion}/modules/rocker[Rocker]: Rocker template engine. * link:{uiVersion}/modules/thymeleaf[Thymeleaf]: Thymeleaf template engine. +==== Remote Procedure Calls (RPC) + * link:{uiVersion}/modules/gRPC[gRPC]: A high-performance, strictly-typed protocol utilizing Protocol Buffers and HTTP/2 multiplexing. Ideal for backend-to-backend communication and polyglot microservices. + * link:{uiVersion}/modules/json-rpc[json-rpc]: A lightweight, stateless, and simple JSON-encoded protocol. Excellent for rapid integrations and environments where standard JSON is preferred. + * link:{uiVersion}/modules/tRPC[tRPC]: A RPC implementation that provides end-to-end type safety directly between your Java backend and TypeScript clients, without requiring intermediate build steps or code generation. + ==== Security * link:{uiVersion}/modules/jasypt[Jasypt]: Encrypted configuration files. * link:{uiVersion}/modules/pac4j[Pac4j]: Security engine module. diff --git a/docs/asciidoc/modules/openapi.adoc b/docs/asciidoc/modules/openapi.adoc index 190a0fd36e..4650e3c61f 100644 --- a/docs/asciidoc/modules/openapi.adoc +++ b/docs/asciidoc/modules/openapi.adoc @@ -411,7 +411,7 @@ Whitespaces (including new lines) are ignored. To introduce a new line, you must |=== | Tag | Main | Controller | Method | Description -|@version 4.0.4 +|@version | [x] | | diff --git a/docs/asciidoc/tRPC.adoc b/docs/asciidoc/modules/tRPC.adoc similarity index 74% rename from docs/asciidoc/tRPC.adoc rename to docs/asciidoc/modules/tRPC.adoc index 88fe7fb329..9581300779 100644 --- a/docs/asciidoc/tRPC.adoc +++ b/docs/asciidoc/modules/tRPC.adoc @@ -2,29 +2,31 @@ 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 -Because tRPC relies heavily on JSON serialization to communicate with the frontend client, a JSON module **must** be installed prior to the `TrpcModule`. +Dependencies: -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. +[dependency, artifactId="jooby-jackson3:Jackson module, jooby-trpc-jackson3:Jackson tRPC JSON implementation, jooby-trpc: tRPC Module"] +. + +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; - -public class App extends Jooby { - { - install(new JacksonModule()); // <1> +import io.jooby.json.Jackson2Module; +import io.jooby.trpc.TrpcModule; +import io.jooby.trpc.TrpcJackson2Module; - install(new TrpcModule()); // <2> +{ + install(new Jackson3Module()); // <1> - trpc(new MovieServiceTrpc_()); // <3> - } + install(new TrpcJackson3Module()); // <2> + + install(new TrpcModule(new MovieServiceTrpc_())); // <3> } ---- @@ -32,21 +34,23 @@ public class App extends Jooby { [source,kotlin,role="secondary"] ---- import io.jooby.kt.Kooby -import io.jooby.json.JacksonModule -import io.jooby.rpc.trpc.TrpcModule +import io.jooby.json.Jackson2Module +import io.jooby.trpc.TrpcModule +import io.jooby.trpc.TrpcJackson2Module -class App : Kooby({ - install(JacksonModule()) // <1> - - install(TrpcModule()) // <2> +{ + install(Jackson3Module()) // <1> - trpc(MovieServiceTrpc_()) // <3> -}) + install(TrpcJackson3Module()) // <2> + + install(TrpcModule(MovieServiceTrpc_())) // <3> +} ---- -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`, `Jackson2Module` 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 +62,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 +95,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 +201,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 +218,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/docs/asciidoc/rpc.adoc b/docs/asciidoc/rpc.adoc deleted file mode 100644 index fb0a5820c3..0000000000 --- a/docs/asciidoc/rpc.adoc +++ /dev/null @@ -1,17 +0,0 @@ -=== Remote Procedure Calls (RPC) - -While standard REST architectures focus on mapping HTTP methods to resources, Remote Procedure Call (RPC) architectures are designed around executing explicit actions or functions. RPC is often the preferred choice for strictly-typed client-server contracts, high-performance microservice communication, and scenarios where a strict resource-based REST model feels overly restrictive. - -Jooby provides first-class support for several RPC protocols. You can run any of these seamlessly alongside your standard HTTP routes on the exact same server instance, sharing the same underlying thread pools and I/O event loops. - -Depending on your client ecosystem and performance requirements, Jooby supports: - -* **gRPC**: A high-performance, strictly-typed protocol utilizing Protocol Buffers and HTTP/2 multiplexing. Ideal for backend-to-backend communication and polyglot microservices. -* **JSON-RPC**: A lightweight, stateless, and simple JSON-encoded protocol. Excellent for rapid integrations and environments where standard JSON is preferred. -* **tRPC**: A RPC implementation that provides end-to-end type safety directly between your Java backend and TypeScript clients, without requiring intermediate build steps or code generation. - -include::gRPC.adoc[] - -include::json-rpc.adoc[] - -include::tRPC.adoc[] diff --git a/docs/asciidoc/web.adoc b/docs/asciidoc/web.adoc index 3ea42db322..6f63aa8da1 100644 --- a/docs/asciidoc/web.adoc +++ b/docs/asciidoc/web.adoc @@ -10,6 +10,4 @@ include::session.adoc[] include::server-sent-event.adoc[] -include::rpc.adoc[] - include::websocket.adoc[] diff --git a/docs/asciidoc/websocket.adoc b/docs/asciidoc/websocket.adoc index af885b71c0..2ad9483d31 100644 --- a/docs/asciidoc/websocket.adoc +++ b/docs/asciidoc/websocket.adoc @@ -89,15 +89,15 @@ You are free to access the HTTP context from the WebSocket configurer or callbac Structured data (like JSON) is supported using the Value API and the javadoc:WebSocket[render, java.lang.Object] method. -To use structured messages, you need a registered javadoc:MessageDecoder[] and javadoc:MessageEncoder[]. In the following example, both are provided by the `JacksonModule`. +To use structured messages, you need a registered javadoc:MessageDecoder[] and javadoc:MessageEncoder[]. In the following example, both are provided by the `Jackson2Module`. .JSON Example [source,java,role="primary"] ---- -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; { - install(new JacksonModule()); // <1> + install(new Jackson2Module()); // <1> ws("/ws", (ctx, configurer) -> { configurer.onMessage((ws, message) -> { @@ -111,10 +111,10 @@ import io.jooby.jackson.JacksonModule; .Kotlin [source,kotlin,role="secondary"] ---- -import io.jooby.jackson.JacksonModule +import io.jooby.jackson.Jackson2Module { - install(JacksonModule()) // <1> + install(Jackson2Module()) // <1> ws("/ws") { ctx, configurer -> configurer.onMessage { ws, message -> @@ -134,10 +134,10 @@ Alternatively, you can explicitly tell the WebSocket which decoder/encoder to us .Explicit Content Types [source,java,role="primary"] ---- -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; { - install(new JacksonModule()); // <1> + install(new Jackson2Module()); // <1> ws("/ws", (ctx, configurer) -> { configurer.onMessage((ws, message) -> { @@ -153,10 +153,10 @@ import io.jooby.jackson.JacksonModule; .Kotlin [source,kotlin,role="secondary"] ---- -import io.jooby.jackson.JacksonModule +import io.jooby.jackson.Jackson2Module { - install(JacksonModule()) // <1> + install(Jackson2Module()) // <1> ws("/ws") { ctx, configurer -> configurer.onMessage { ws, message -> diff --git a/docs/js/styles/theme.css b/docs/js/styles/theme.css index 3d52957fc4..ff58190550 100644 --- a/docs/js/styles/theme.css +++ b/docs/js/styles/theme.css @@ -28,7 +28,7 @@ /* Layout */ --sidebar-width: 300px; - --content-max-width: 900px; + --content-max-width: 1050px; /* INCREASED from 900px */ --border-radius: 6px; /* Typography Stacks */ @@ -129,7 +129,7 @@ li { margin-bottom: 0.35rem; } #content, #footer { max-width: var(--content-max-width); margin: 0 auto; - padding: 2.5rem 3rem; + padding: 2.5rem 1.5rem; /* REDUCED horizontal padding */ } } @@ -558,13 +558,13 @@ pre.highlightjs.badges-loaded code { opacity: 1; } ========================================================================== */ table.tableblock { width: 100%; - table-layout: fixed !important; + table-layout: auto; /* FIXED: Let the browser respect Asciidoc col widths */ border-collapse: separate; border-spacing: 0; margin: 1.5rem 0; border: 1px solid var(--border-color); border-radius: var(--border-radius); - overflow: hidden; + overflow-x: auto; } table.tableblock td, table.tableblock th { @@ -575,7 +575,7 @@ table.tableblock td, table.tableblock th { text-align: left; vertical-align: top; word-wrap: break-word; - overflow-wrap: anywhere; + overflow-wrap: break-word; /* FIXED: Removed 'anywhere' word chopping */ } table.tableblock thead th { @@ -583,12 +583,6 @@ table.tableblock thead th { font-weight: 600; border-bottom: 2px solid var(--border-color); color: var(--heading-color); - white-space: nowrap; -} - -table.tableblock:not(:has(colgroup col[style*="width"])) td:first-child { - white-space: nowrap; - width: 1%; } table.tableblock td:first-child { font-weight: 500; color: var(--heading-color); } @@ -800,4 +794,3 @@ html[data-theme="dark"] .DocSearch-Button-Keys kbd { color: #e2e8f0 !important; background: #334155 !important; } - diff --git a/docs/src/main/java/io/jooby/adoc/DocApp.java b/docs/src/main/java/io/jooby/adoc/DocApp.java index 1d178aca39..ef31b5ed2d 100644 --- a/docs/src/main/java/io/jooby/adoc/DocApp.java +++ b/docs/src/main/java/io/jooby/adoc/DocApp.java @@ -7,7 +7,9 @@ import static org.slf4j.helpers.NOPLogger.NOP_LOGGER; +import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.StandardCopyOption; import java.util.Arrays; import java.util.List; @@ -51,6 +53,7 @@ public static void main(String[] args) throws Exception { runApp(args, server, DocApp::new); Path outdir = basedir.resolve("asciidoc").resolve("site"); + Path themeCssDir = basedir.resolve("js").resolve("styles"); DirectoryWatcher watcher = DirectoryWatcher.builder() @@ -69,6 +72,8 @@ public static void main(String[] args) throws Exception { } catch (Exception x) { log.error("Site build resulted in exception", x); } + } else if (file.toString().endsWith("theme.css")) { + Files.copy(file, outdir.resolve("js").resolve("styles").resolve("theme.css"), StandardCopyOption.REPLACE_EXISTING); } } }) diff --git a/jooby/pom.xml b/jooby/pom.xml index c99be0e8ab..de1bba9eb4 100644 --- a/jooby/pom.xml +++ b/jooby/pom.xml @@ -6,7 +6,7 @@ io.jooby jooby-project - 4.2.0 + 4.3.0 jooby jooby diff --git a/jooby/src/main/java/io/jooby/Jooby.java b/jooby/src/main/java/io/jooby/Jooby.java index df39736716..c0bcb5ce2b 100644 --- a/jooby/src/main/java/io/jooby/Jooby.java +++ b/jooby/src/main/java/io/jooby/Jooby.java @@ -37,8 +37,6 @@ import io.jooby.internal.RouterImpl; import io.jooby.output.OutputFactory; import io.jooby.problem.ProblemDetailsHandler; -import io.jooby.rpc.jsonrpc.JsonRpcModule; -import io.jooby.rpc.jsonrpc.JsonRpcService; import io.jooby.value.ValueFactory; /** @@ -60,7 +58,7 @@ * * } * - * More documentation at jooby.io + *

More documentation at jooby.io * * @author edgar * @since 2.0.0 @@ -104,8 +102,6 @@ public class Jooby implements Router, Registry { private List locales; - private Map dispatchers; - private boolean lateInit; private String name; @@ -299,7 +295,8 @@ public String getContextPath() { * * } * - * Lazy creation configures and setup SubApp correctly, the next example won't work: + *

Lazy creation configures and setup SubApp correctly, the next example won't + * work: * *

{@code
    * SubApp app = new SubApp();
@@ -307,8 +304,9 @@ public String getContextPath() {
    *
    * }
* - * Note: you must take care of application services across the applications. For example make sure - * you don't configure the same service twice or more in the main and imported applications too. + *

Note: you must take care of application services across the applications. For example make + * sure you don't configure the same service twice or more in the main and imported applications + * too. * * @param factory Application factory. * @return Created routes. @@ -331,7 +329,7 @@ public String getContextPath() { * * } * - * Lazy creation allows to configure and setup SubApp correctly, the next example + *

Lazy creation allows to configure and setup SubApp correctly, the next example * won't work: * *

{@code
@@ -340,8 +338,9 @@ public String getContextPath() {
    *
    * }
* - * Note: you must take care of application services across the applications. For example make sure - * you don't configure the same service twice or more in the main and imported applications too. + *

Note: you must take care of application services across the applications. For example make + * sure you don't configure the same service twice or more in the main and imported applications + * too. * * @param path Path prefix. * @param factory Application factory. @@ -370,7 +369,7 @@ public String getContextPath() { * * } * - * Lazy creation allows to configure and setup SubApp correctly, the next example + *

Lazy creation allows to configure and setup SubApp correctly, the next example * won't work: * *

{@code
@@ -379,8 +378,9 @@ public String getContextPath() {
    *
    * }
* - * Note: you must take care of application services across the applications. For example make sure - * you don't configure the same service twice or more in the main and imported applications too. + *

Note: you must take care of application services across the applications. For example make + * sure you don't configure the same service twice or more in the main and imported applications + * too. * * @param path Sub path. * @param predicate HTTP predicate. @@ -414,7 +414,7 @@ public Jooby install( * * } * - * Lazy creation allows to configure and setup SubApp correctly, the next example + *

Lazy creation allows to configure and setup SubApp correctly, the next example * won't work: * *

{@code
@@ -423,8 +423,9 @@ public Jooby install(
    *
    * }
* - * Note: you must take care of application services across the applications. For example make sure - * you don't configure the same service twice or more in the main and imported applications too. + *

Note: you must take care of application services across the applications. For example make + * sure you don't configure the same service twice or more in the main and imported applications + * too. * * @param predicate HTTP predicate. * @param factory Application factory. @@ -493,48 +494,6 @@ public Route.Set mount(@NonNull Router router) { return mount("/", router); } - /** - * Mounts and registers a JSON-RPC service at the specified custom path. - * - *

This method initializes a JSON-RPC dispatcher for the given path if one does not already - * exist, installs the dispatcher module into the application, and binds the provided {@link - * JsonRpcService} to it. Multiple services can be added to the same path. - * - * @param path The URL path where the JSON-RPC endpoint will be exposed (e.g., "/api/rpc"). - * @param service The {@link JsonRpcService} instance containing the RPC methods to expose. Must - * not be null. - * @return This {@link Jooby} instance to allow for method chaining. - */ - public Jooby jsonRpc(String path, @NonNull JsonRpcService service) { - if (dispatchers == null) { - dispatchers = new HashMap<>(); - } - dispatchers - .computeIfAbsent( - Router.normalizePath(path), - normalizedPath -> { - var dispatcher = new JsonRpcModule(normalizedPath); - install(dispatcher); - return dispatcher; - }) - .add(service); - return this; - } - - /** - * Mounts and registers a JSON-RPC service at the default path {@code "/rpc"}. - * - *

This is a convenience method that delegates to {@link #jsonRpc(String, JsonRpcService)} - * using the default endpoint path. - * - * @param service The {@link JsonRpcService} instance containing the RPC methods to expose. Must - * not be null. - * @return This {@link Jooby} instance to allow for method chaining. - */ - public Jooby jsonRpc(@NonNull JsonRpcService service) { - return jsonRpc("/rpc", service); - } - /** * Registers a tRPC router within the application. * @@ -556,19 +515,12 @@ public Route.Set trpc(@NonNull Extension trpcRouter) { * @return Route set. */ public Route.Set mvc(@NonNull Extension router) { - if (router instanceof JsonRpcService jsonRpcService) { - jsonRpc(jsonRpcService); - // NOOP - return new Route.Set(Collections.emptyList()); - } else { - try { - int start = this.router.getRoutes().size(); - router.install(this); - return new Route.Set( - this.router.getRoutes().subList(start, this.router.getRoutes().size())); - } catch (Exception cause) { - throw SneakyThrows.propagate(cause); - } + try { + int start = this.router.getRoutes().size(); + router.install(this); + return new Route.Set(this.router.getRoutes().subList(start, this.router.getRoutes().size())); + } catch (Exception cause) { + throw SneakyThrows.propagate(cause); } } @@ -1521,6 +1473,5 @@ private static void copyState(Jooby source, Jooby dest) { dest.readyCallbacks = source.readyCallbacks; dest.startingCallbacks = source.startingCallbacks; dest.stopCallbacks = source.stopCallbacks; - dest.dispatchers = source.dispatchers; } } diff --git a/jooby/src/main/java/module-info.java b/jooby/src/main/java/module-info.java index ce4d5c509e..8fbbbf03ce 100644 --- a/jooby/src/main/java/module-info.java +++ b/jooby/src/main/java/module-info.java @@ -15,9 +15,7 @@ exports io.jooby.value; exports io.jooby.output; /* 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 2674e96225..d97b8599e9 100644 --- a/modules/jooby-apt/pom.xml +++ b/modules/jooby-apt/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-apt jooby-apt @@ -38,6 +38,20 @@ test + + io.jooby + jooby-trpc + ${jooby.version} + test + + + + io.jooby + jooby-jsonrpc + ${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..10dfe27291 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,10 +266,10 @@ 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.JsonRpc"); + 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.JsonRpc"); // Add MCP Annotations supportedTypes.add("io.jooby.annotation.mcp.McpCompletion"); supportedTypes.add("io.jooby.annotation.mcp.McpTool"); diff --git a/modules/jooby-apt/src/main/java/io/jooby/internal/apt/JsonRpcRoute.java b/modules/jooby-apt/src/main/java/io/jooby/internal/apt/JsonRpcRoute.java index d84288baaf..54c43c73ad 100644 --- a/modules/jooby-apt/src/main/java/io/jooby/internal/apt/JsonRpcRoute.java +++ b/modules/jooby-apt/src/main/java/io/jooby/internal/apt/JsonRpcRoute.java @@ -22,7 +22,8 @@ public JsonRpcRoute(JsonRpcRouter router, ExecutableElement method) { } public String getJsonRpcMethodName() { - var annotation = AnnotationSupport.findAnnotationByName(method, "io.jooby.annotation.JsonRpc"); + var annotation = + AnnotationSupport.findAnnotationByName(method, "io.jooby.annotation.jsonrpc.JsonRpc"); if (annotation != null) { var val = AnnotationSupport.findAnnotationValue(annotation, VALUE).stream().findFirst().orElse(""); @@ -74,7 +75,7 @@ public List generateJsonRpcDispatchCase(boolean kt) { private List generateRpcParameter(boolean kt, Consumer arguments) { var statements = new ArrayList(); - var decoderInterface = "io.jooby.rpc.jsonrpc.JsonRpcDecoder"; + var decoderInterface = "io.jooby.jsonrpc.JsonRpcDecoder"; int baseIndent = 10; for (var parameter : parameters) { diff --git a/modules/jooby-apt/src/main/java/io/jooby/internal/apt/JsonRpcRouter.java b/modules/jooby-apt/src/main/java/io/jooby/internal/apt/JsonRpcRouter.java index 36dce8da9a..20c5a54abb 100644 --- a/modules/jooby-apt/src/main/java/io/jooby/internal/apt/JsonRpcRouter.java +++ b/modules/jooby-apt/src/main/java/io/jooby/internal/apt/JsonRpcRouter.java @@ -27,7 +27,7 @@ public JsonRpcRouter(MvcContext context, TypeElement clazz) { public static JsonRpcRouter parse(MvcContext context, TypeElement controller) { var router = new JsonRpcRouter(context, controller); var classAnnotation = - AnnotationSupport.findAnnotationByName(controller, "io.jooby.annotation.JsonRpc"); + AnnotationSupport.findAnnotationByName(controller, "io.jooby.annotation.jsonrpc.JsonRpc"); var explicitlyAnnotated = new ArrayList(); var allPublicMethods = new ArrayList(); @@ -47,7 +47,7 @@ public static JsonRpcRouter parse(MvcContext context, TypeElement controller) { || methodName.equals("clone")) continue; allPublicMethods.add(method); - if (AnnotationSupport.findAnnotationByName(method, "io.jooby.annotation.JsonRpc") + if (AnnotationSupport.findAnnotationByName(method, "io.jooby.annotation.jsonrpc.JsonRpc") != null) { explicitlyAnnotated.add(method); } @@ -75,7 +75,8 @@ public String getGeneratedType() { } private String getJsonRpcNamespace() { - var annotation = AnnotationSupport.findAnnotationByName(clazz, "io.jooby.annotation.JsonRpc"); + var annotation = + AnnotationSupport.findAnnotationByName(clazz, "io.jooby.annotation.jsonrpc.JsonRpc"); if (annotation != null) { return AnnotationSupport.findAnnotationValue(annotation, VALUE).stream() .findFirst() @@ -116,7 +117,7 @@ public String toSourceCode(boolean kt) throws IOException { buffer.append( statement( indent(6), - "app.services.listOf(io.jooby.rpc.jsonrpc.JsonRpcService::class.java).add(this)")); + "app.services.listOf(io.jooby.jsonrpc.JsonRpcService::class.java).add(this)")); buffer.append(statement(indent(4), "}", System.lineSeparator())); buffer.append(statement(indent(4), "override fun getMethods(): List {")); @@ -127,13 +128,12 @@ public String toSourceCode(boolean kt) throws IOException { statement( indent(4), "override fun execute(ctx: io.jooby.Context, req:" - + " io.jooby.rpc.jsonrpc.JsonRpcRequest): Any? {")); + + " io.jooby.jsonrpc.JsonRpcRequest): Any? {")); buffer.append(statement(indent(6), "val c = factory.apply(ctx)")); buffer.append(statement(indent(6), "val method = req.method")); buffer.append( statement( - indent(6), - "val parser = ctx.require(io.jooby.rpc.jsonrpc.JsonRpcParser::class.java)")); + indent(6), "val parser = ctx.require(io.jooby.jsonrpc.JsonRpcParser::class.java)")); buffer.append(statement(indent(6), "return when(method) {")); for (int i = 0; i < getRoutes().size(); i++) { @@ -146,7 +146,7 @@ public String toSourceCode(boolean kt) throws IOException { statement( indent(8), "else -> throw" - + " io.jooby.rpc.jsonrpc.JsonRpcException(io.jooby.rpc.jsonrpc.JsonRpcErrorCode.METHOD_NOT_FOUND,", + + " io.jooby.jsonrpc.JsonRpcException(io.jooby.jsonrpc.JsonRpcErrorCode.METHOD_NOT_FOUND,", string("Method not found: $method"), ")")); buffer.append(statement(indent(6), "}")); @@ -159,7 +159,7 @@ public String toSourceCode(boolean kt) throws IOException { buffer.append( statement( indent(6), - "app.getServices().listOf(io.jooby.rpc.jsonrpc.JsonRpcService.class).add(this);")); + "app.getServices().listOf(io.jooby.jsonrpc.JsonRpcService.class).add(this);")); buffer.append(statement(indent(4), "}", System.lineSeparator())); buffer.append(statement(indent(4), "@Override")); @@ -171,13 +171,12 @@ public String toSourceCode(boolean kt) throws IOException { buffer.append( statement( indent(4), - "public Object execute(io.jooby.Context ctx, io.jooby.rpc.jsonrpc.JsonRpcRequest req)" + "public Object execute(io.jooby.Context ctx, io.jooby.jsonrpc.JsonRpcRequest req)" + " throws Exception {")); buffer.append(statement(indent(6), "var c = factory.apply(ctx);")); buffer.append(statement(indent(6), "var method = req.getMethod();")); buffer.append( - statement( - indent(6), "var parser = ctx.require(io.jooby.rpc.jsonrpc.JsonRpcParser.class);")); + statement(indent(6), "var parser = ctx.require(io.jooby.jsonrpc.JsonRpcParser.class);")); buffer.append(statement(indent(6), "switch(method) {")); for (int i = 0; i < getRoutes().size(); i++) { @@ -191,7 +190,7 @@ public String toSourceCode(boolean kt) throws IOException { statement( indent(10), "throw new" - + " io.jooby.rpc.jsonrpc.JsonRpcException(io.jooby.rpc.jsonrpc.JsonRpcErrorCode.METHOD_NOT_FOUND," + + " io.jooby.jsonrpc.JsonRpcException(io.jooby.jsonrpc.JsonRpcErrorCode.METHOD_NOT_FOUND," + " ", string("Method not found:"), " + method);")); @@ -204,7 +203,7 @@ public String toSourceCode(boolean kt) throws IOException { .replace("${imports}", imports) .replace("${className}", generateTypeName) .replace("${generatedClassName}", generatedClass) - .replace("${implements}", "io.jooby.rpc.jsonrpc.JsonRpcService, io.jooby.Extension") + .replace("${implements}", "io.jooby.jsonrpc.JsonRpcService") .replace("${constructors}", constructors(generatedClass, kt)) .replace("${methods}", trimr(buffer)); } 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..518eb8cb23 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,23 +45,23 @@ 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() .flatMap(it -> AnnotationSupport.findAnnotationValue(it, VALUE).stream().findFirst()) .orElse(method.getSimpleName().toString()); - return Stream.of("trpc", namespace + procedure) + return Stream.of(namespace + procedure) .map(segment -> segment.startsWith("/") ? segment.substring(1) : segment) .collect(Collectors.joining("/", "/", "")); } @@ -86,7 +86,8 @@ public List generateMapping(boolean kt, String routerName) { isSuspendFun() ? "" : "app.", dslMethod, "(", - string(path.startsWith("/") ? path : "/" + path), + "path + ", + string(path), ", ", context.pipeline( getReturnType().getRawType(), methodReference(kt, thisRef, targetMethod)))); @@ -138,10 +139,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 +174,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 +434,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 +468,7 @@ public List generateHandlerCall(boolean kt) { buffer.add( statement( indent(4), - "io.jooby.rpc.trpc.TrpcDecoder<", + "io.jooby.trpc.TrpcDecoder<", genericType, "> ", parameterName, @@ -527,7 +528,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 +536,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 +544,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 +552,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 +560,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 +571,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 +579,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 +587,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 +596,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 +606,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..fa6c8ee4b1 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); @@ -97,12 +100,12 @@ public String toSourceCode(boolean kt) throws IOException { buffer.append(indent(4)).append("@Throws(Exception::class)").append(System.lineSeparator()); buffer .append(indent(4)) - .append("override fun install(app: io.jooby.Jooby) {") + .append("override fun install(path: String, app: io.jooby.Jooby) {") .append(System.lineSeparator()); } else { buffer .append(indent(4)) - .append("public void install(io.jooby.Jooby app) throws Exception {") + .append("public void install(String path, io.jooby.Jooby app) throws Exception {") .append(System.lineSeparator()); } @@ -127,7 +130,7 @@ public String toSourceCode(boolean kt) throws IOException { .replace("${imports}", imports) .replace("${className}", generateTypeName) .replace("${generatedClassName}", generatedClass) - .replace("${implements}", "io.jooby.Extension") + .replace("${implements}", "io.jooby.trpc.TrpcService") .replace("${constructors}", constructors(generatedClass, kt)) .replace("${methods}", trimr(buffer)); } diff --git a/modules/jooby-apt/src/test/java/tests/i3863/Issue3863.java b/modules/jooby-apt/src/test/java/tests/i3863/Issue3863.java index c16c70bcdc..1480d8eb5a 100644 --- a/modules/jooby-apt/src/test/java/tests/i3863/Issue3863.java +++ b/modules/jooby-apt/src/test/java/tests/i3863/Issue3863.java @@ -24,8 +24,8 @@ public void trpcQuery() throws Exception { .withTrpcCode( source -> { assertThat(source) - .contains("app.get(\"/trpc/users.getUserById\", this::trpcGetUserById);") - .contains("app.post(\"/trpc/users.createUser\", this::trpcCreateUser);"); + .contains("app.get(path + \"/users.getUserById\", this::trpcGetUserById);") + .contains("app.post(path + \"/users.createUser\", this::trpcCreateUser);"); }); } @@ -36,8 +36,8 @@ public void mixedAnnotation() throws Exception { source -> { assertThat(source) // tRPC - .contains("app.get(\"/trpc/users.getUserById\", this::trpcGetUserById);") - .contains("app.post(\"/trpc/users.createUser\", this::trpcCreateUser);"); + .contains("app.get(path + \"/users.getUserById\", this::trpcGetUserById);") + .contains("app.post(path + \"/users.createUser\", this::trpcCreateUser);"); }) .withSourceCode( source -> { @@ -55,10 +55,10 @@ public void mixedMutation() throws Exception { source -> { assertThat(source) // tRPC - .contains("app.post(\"/trpc/users.createUser\", this::trpcCreateUser);") - .contains("app.post(\"/trpc/users.updateUser\", this::trpcUpdateUser);") - .contains("app.post(\"/trpc/users.patchUser\", this::trpcPatchUser);") - .contains("app.post(\"/trpc/users.deleteUser\", this::trpcDeleteUser);"); + .contains("app.post(path + \"/users.createUser\", this::trpcCreateUser);") + .contains("app.post(path + \"/users.updateUser\", this::trpcUpdateUser);") + .contains("app.post(path + \"/users.patchUser\", this::trpcPatchUser);") + .contains("app.post(path + \"/users.deleteUser\", this::trpcDeleteUser);"); }) .withSourceCode( source -> { @@ -78,8 +78,8 @@ public void overloadTrpc() throws Exception { source -> { assertThat(source) // tRPC - .contains("app.get(\"/trpc/users.ping\", this::trpcPing);") - .contains("app.get(\"/trpc/users.ping.since\", this::trpcPingInteger);"); + .contains("app.get(path + \"/users.ping\", this::trpcPing);") + .contains("app.get(path + \"/users.ping.since\", this::trpcPingInteger);"); }); } } 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-apt/src/test/java/tests/i3864/CustomNaming.java b/modules/jooby-apt/src/test/java/tests/i3864/CustomNaming.java index 272594fc2a..d40705f7d5 100644 --- a/modules/jooby-apt/src/test/java/tests/i3864/CustomNaming.java +++ b/modules/jooby-apt/src/test/java/tests/i3864/CustomNaming.java @@ -5,7 +5,7 @@ */ package tests.i3864; -import io.jooby.annotation.JsonRpc; +import io.jooby.annotation.jsonrpc.JsonRpc; @JsonRpc("movies") public class CustomNaming { diff --git a/modules/jooby-apt/src/test/java/tests/i3864/DIService.java b/modules/jooby-apt/src/test/java/tests/i3864/DIService.java index fa74d08077..bd4e63d597 100644 --- a/modules/jooby-apt/src/test/java/tests/i3864/DIService.java +++ b/modules/jooby-apt/src/test/java/tests/i3864/DIService.java @@ -5,7 +5,7 @@ */ package tests.i3864; -import io.jooby.annotation.JsonRpc; +import io.jooby.annotation.jsonrpc.JsonRpc; import jakarta.inject.Inject; @JsonRpc diff --git a/modules/jooby-apt/src/test/java/tests/i3864/DefaultMapping.java b/modules/jooby-apt/src/test/java/tests/i3864/DefaultMapping.java index 5ae97461c7..f1e888ccee 100644 --- a/modules/jooby-apt/src/test/java/tests/i3864/DefaultMapping.java +++ b/modules/jooby-apt/src/test/java/tests/i3864/DefaultMapping.java @@ -5,7 +5,7 @@ */ package tests.i3864; -import io.jooby.annotation.JsonRpc; +import io.jooby.annotation.jsonrpc.JsonRpc; @JsonRpc("default") public class DefaultMapping { diff --git a/modules/jooby-apt/src/test/java/tests/i3864/EmptyNamespace.java b/modules/jooby-apt/src/test/java/tests/i3864/EmptyNamespace.java index 52f517a4f7..93f0645665 100644 --- a/modules/jooby-apt/src/test/java/tests/i3864/EmptyNamespace.java +++ b/modules/jooby-apt/src/test/java/tests/i3864/EmptyNamespace.java @@ -5,7 +5,7 @@ */ package tests.i3864; -import io.jooby.annotation.JsonRpc; +import io.jooby.annotation.jsonrpc.JsonRpc; @JsonRpc public class EmptyNamespace { diff --git a/modules/jooby-apt/src/test/java/tests/i3864/ExplicitMapping.java b/modules/jooby-apt/src/test/java/tests/i3864/ExplicitMapping.java index 107cb4e99d..5b273cceb1 100644 --- a/modules/jooby-apt/src/test/java/tests/i3864/ExplicitMapping.java +++ b/modules/jooby-apt/src/test/java/tests/i3864/ExplicitMapping.java @@ -5,7 +5,7 @@ */ package tests.i3864; -import io.jooby.annotation.JsonRpc; +import io.jooby.annotation.jsonrpc.JsonRpc; @JsonRpc("explicit") public class ExplicitMapping { diff --git a/modules/jooby-apt/src/test/java/tests/i3864/Issue3868.java b/modules/jooby-apt/src/test/java/tests/i3864/Issue3868.java index 8c97f4ab48..47a1065a23 100644 --- a/modules/jooby-apt/src/test/java/tests/i3864/Issue3868.java +++ b/modules/jooby-apt/src/test/java/tests/i3864/Issue3868.java @@ -20,13 +20,13 @@ public void topLevelAnnotationMakeAllPublicJSONRPC() throws Exception { assertThat(source) .contains( "public class DefaultMappingRpc_ implements" - + " io.jooby.rpc.jsonrpc.JsonRpcService, io.jooby.Extension {") + + " io.jooby.jsonrpc.JsonRpcService {") .contains("public java.util.List getMethods() {") .contains( "return java.util.List.of(\"default.rpcMethod1\", \"default.rpcMethod2\")") .contains( "public Object execute(io.jooby.Context ctx," - + " io.jooby.rpc.jsonrpc.JsonRpcRequest req) throws Exception {"); + + " io.jooby.jsonrpc.JsonRpcRequest req) throws Exception {"); }); } diff --git a/modules/jooby-apt/src/test/java/tests/i3864/NullSupport.java b/modules/jooby-apt/src/test/java/tests/i3864/NullSupport.java index be25a2df70..0a14b6ff98 100644 --- a/modules/jooby-apt/src/test/java/tests/i3864/NullSupport.java +++ b/modules/jooby-apt/src/test/java/tests/i3864/NullSupport.java @@ -6,7 +6,7 @@ package tests.i3864; import edu.umd.cs.findbugs.annotations.NonNull; -import io.jooby.annotation.JsonRpc; +import io.jooby.annotation.jsonrpc.JsonRpc; @JsonRpc public class NullSupport { diff --git a/modules/jooby-apt/src/test/java/tests/i3864/WithContext.java b/modules/jooby-apt/src/test/java/tests/i3864/WithContext.java index 93162b2e1d..be4cc8c5bc 100644 --- a/modules/jooby-apt/src/test/java/tests/i3864/WithContext.java +++ b/modules/jooby-apt/src/test/java/tests/i3864/WithContext.java @@ -6,7 +6,7 @@ package tests.i3864; import io.jooby.Context; -import io.jooby.annotation.JsonRpc; +import io.jooby.annotation.jsonrpc.JsonRpc; @JsonRpc("movies") public class WithContext { diff --git a/modules/jooby-avaje-inject/pom.xml b/modules/jooby-avaje-inject/pom.xml index d1ef683b9f..5e59a9acc9 100644 --- a/modules/jooby-avaje-inject/pom.xml +++ b/modules/jooby-avaje-inject/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-avaje-inject jooby-avaje-inject diff --git a/modules/jooby-avaje-inject/src/main/java/io/jooby/avaje/inject/AvajeInjectModule.java b/modules/jooby-avaje-inject/src/main/java/io/jooby/avaje/inject/AvajeInjectModule.java index 310a18d62a..36e768f029 100644 --- a/modules/jooby-avaje-inject/src/main/java/io/jooby/avaje/inject/AvajeInjectModule.java +++ b/modules/jooby-avaje-inject/src/main/java/io/jooby/avaje/inject/AvajeInjectModule.java @@ -39,7 +39,7 @@ */ public class AvajeInjectModule implements Extension { - private final BeanScopeBuilder beanScope; + private final BeanScopeBuilder scopeBuilder; public static AvajeInjectModule of() { return new AvajeInjectModule(BeanScope.builder()); @@ -49,8 +49,8 @@ public static AvajeInjectModule of(BeanScopeBuilder beanScope) { return new AvajeInjectModule(beanScope); } - public AvajeInjectModule(@NonNull BeanScopeBuilder beanScope) { - this.beanScope = beanScope; + public AvajeInjectModule(@NonNull BeanScopeBuilder scopeBuilder) { + this.scopeBuilder = scopeBuilder; } @Override @@ -60,7 +60,6 @@ public boolean lateinit() { @Override public void install(Jooby application) { - application .getServices() .entrySet() @@ -69,20 +68,20 @@ public void install(Jooby application) { var key = e.getKey(); var provider = e.getValue(); if (key.getName() == null) { - beanScope.provideDefault(key.getType(), provider::get); + scopeBuilder.provideDefault(key.getType(), provider::get); } else { - beanScope.bean(key.getName(), key.getType(), provider); + scopeBuilder.bean(key.getName(), key.getType(), provider); } }); final var environment = application.getEnvironment(); - beanScope.bean(Environment.class, environment); - beanScope.profiles(environment.getActiveNames().toArray(String[]::new)); + scopeBuilder.bean(Environment.class, environment); + scopeBuilder.profiles(environment.getActiveNames().toArray(String[]::new)); // configuration properties final var config = environment.getConfig(); - beanScope.configPlugin(new JoobyPropertyPlugin(config)); + scopeBuilder.configPlugin(new JoobyPropertyPlugin(config)); for (var entry : config.entrySet()) { String name = entry.getKey(); @@ -91,9 +90,11 @@ public void install(Jooby application) { if (value instanceof List values) { value = values.stream().map(Object::toString).collect(Collectors.joining(",")); } - beanScope.bean(name, String.class, value.toString()); + scopeBuilder.bean(name, String.class, value.toString()); } - application.registry(new AvajeInjectRegistry(beanScope.build())); + var beanScope = scopeBuilder.build(); + application.registry(new AvajeInjectRegistry(beanScope)); + application.onStop(beanScope); } } diff --git a/modules/jooby-avaje-jsonb/pom.xml b/modules/jooby-avaje-jsonb/pom.xml index 595bd88f8d..dd6fa118fc 100644 --- a/modules/jooby-avaje-jsonb/pom.xml +++ b/modules/jooby-avaje-jsonb/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-avaje-jsonb jooby-avaje-jsonb 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..b3a5934351 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,19 +10,12 @@ 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; import io.jooby.*; import io.jooby.internal.avaje.jsonb.*; import io.jooby.output.Output; -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); - return jsonb; + return Jsonb.builder(); } } diff --git a/modules/jooby-avaje-validator/pom.xml b/modules/jooby-avaje-validator/pom.xml index ad38cebccb..056f71a3c8 100644 --- a/modules/jooby-avaje-validator/pom.xml +++ b/modules/jooby-avaje-validator/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-avaje-validator jooby-avaje-validator diff --git a/modules/jooby-awssdk-v1/pom.xml b/modules/jooby-awssdk-v1/pom.xml index da13fc02dc..f03f433f5e 100644 --- a/modules/jooby-awssdk-v1/pom.xml +++ b/modules/jooby-awssdk-v1/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-awssdk-v1 jooby-awssdk-v1 diff --git a/modules/jooby-awssdk-v2/pom.xml b/modules/jooby-awssdk-v2/pom.xml index d1c2c4563a..9429768e6c 100644 --- a/modules/jooby-awssdk-v2/pom.xml +++ b/modules/jooby-awssdk-v2/pom.xml @@ -6,13 +6,13 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-awssdk-v2 jooby-awssdk-v2 - 2.42.23 + 2.42.28 diff --git a/modules/jooby-bom/pom.xml b/modules/jooby-bom/pom.xml index e43a207deb..2bf4ccce71 100644 --- a/modules/jooby-bom/pom.xml +++ b/modules/jooby-bom/pom.xml @@ -7,14 +7,14 @@ io.jooby modules - 4.2.0 + 4.3.0 io.jooby jooby-bom jooby-bom pom - 4.2.0 + 4.3.0 Jooby (Bill of Materials) https://jooby.io diff --git a/modules/jooby-caffeine/pom.xml b/modules/jooby-caffeine/pom.xml index 40c0d08a13..f7ed68d5ac 100644 --- a/modules/jooby-caffeine/pom.xml +++ b/modules/jooby-caffeine/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-caffeine jooby-caffeine diff --git a/modules/jooby-camel/pom.xml b/modules/jooby-camel/pom.xml index 33fc55abea..e7eb3b656f 100644 --- a/modules/jooby-camel/pom.xml +++ b/modules/jooby-camel/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-camel jooby-camel diff --git a/modules/jooby-cli/pom.xml b/modules/jooby-cli/pom.xml index 769164aac1..14447122b6 100644 --- a/modules/jooby-cli/pom.xml +++ b/modules/jooby-cli/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-cli jooby-cli diff --git a/modules/jooby-commons-email/pom.xml b/modules/jooby-commons-email/pom.xml index fe849c63f0..d95b472561 100644 --- a/modules/jooby-commons-email/pom.xml +++ b/modules/jooby-commons-email/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-commons-email jooby-commons-email diff --git a/modules/jooby-conscrypt/pom.xml b/modules/jooby-conscrypt/pom.xml index 24f6ac6955..c2d8352878 100644 --- a/modules/jooby-conscrypt/pom.xml +++ b/modules/jooby-conscrypt/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-conscrypt jooby-conscrypt diff --git a/modules/jooby-db-scheduler/pom.xml b/modules/jooby-db-scheduler/pom.xml index 702d064a65..79bee0e642 100644 --- a/modules/jooby-db-scheduler/pom.xml +++ b/modules/jooby-db-scheduler/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-db-scheduler jooby-db-scheduler diff --git a/modules/jooby-distribution/pom.xml b/modules/jooby-distribution/pom.xml index 3cef55da9a..9f23b9a6ce 100644 --- a/modules/jooby-distribution/pom.xml +++ b/modules/jooby-distribution/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-distribution jooby-distribution diff --git a/modules/jooby-ebean/pom.xml b/modules/jooby-ebean/pom.xml index 175923f8ca..eb8e2408c8 100644 --- a/modules/jooby-ebean/pom.xml +++ b/modules/jooby-ebean/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-ebean jooby-ebean diff --git a/modules/jooby-flyway/pom.xml b/modules/jooby-flyway/pom.xml index 2bed2479c2..e4468140c4 100644 --- a/modules/jooby-flyway/pom.xml +++ b/modules/jooby-flyway/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-flyway jooby-flyway diff --git a/modules/jooby-freemarker/pom.xml b/modules/jooby-freemarker/pom.xml index a904013340..7702269521 100644 --- a/modules/jooby-freemarker/pom.xml +++ b/modules/jooby-freemarker/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-freemarker jooby-freemarker 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-gradle-setup/pom.xml b/modules/jooby-gradle-setup/pom.xml index d5a27aa174..a24be40137 100644 --- a/modules/jooby-gradle-setup/pom.xml +++ b/modules/jooby-gradle-setup/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-gradle-setup jooby-gradle-setup diff --git a/modules/jooby-graphiql/pom.xml b/modules/jooby-graphiql/pom.xml index 41c7f092ae..c7cbedda46 100644 --- a/modules/jooby-graphiql/pom.xml +++ b/modules/jooby-graphiql/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-graphiql jooby-graphiql diff --git a/modules/jooby-graphql/pom.xml b/modules/jooby-graphql/pom.xml index b3bd8126c4..1652e41131 100644 --- a/modules/jooby-graphql/pom.xml +++ b/modules/jooby-graphql/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-graphql jooby-graphql diff --git a/modules/jooby-grpc/pom.xml b/modules/jooby-grpc/pom.xml index 942b5fb842..8c38b0d926 100644 --- a/modules/jooby-grpc/pom.xml +++ b/modules/jooby-grpc/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-grpc jooby-grpc diff --git a/modules/jooby-grpc/src/main/java/io/jooby/grpc/GrpcModule.java b/modules/jooby-grpc/src/main/java/io/jooby/grpc/GrpcModule.java index cd52e5b375..32438beb89 100644 --- a/modules/jooby-grpc/src/main/java/io/jooby/grpc/GrpcModule.java +++ b/modules/jooby-grpc/src/main/java/io/jooby/grpc/GrpcModule.java @@ -19,7 +19,7 @@ import io.jooby.rpc.grpc.GrpcProcessor; /** - * Native gRPC extension for Jooby. * + * Native gRPC extension for Jooby. * *

This module allows you to run strictly-typed gRPC services alongside standard Jooby HTTP * routes on the exact same port. It completely bypasses standard HTTP/1.1 pipelines in favor of a diff --git a/modules/jooby-grpc/src/main/java/module-info.java b/modules/jooby-grpc/src/main/java/module-info.java index 83978449fc..c690bc2e26 100644 --- a/modules/jooby-grpc/src/main/java/module-info.java +++ b/modules/jooby-grpc/src/main/java/module-info.java @@ -3,7 +3,62 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -/** GraphQL module. */ + +import org.slf4j.bridge.SLF4JBridgeHandler; + +/** + * Native gRPC extension for Jooby. + * + *

This module allows you to run strictly-typed gRPC services alongside standard Jooby HTTP + * routes on the exact same port. It completely bypasses standard HTTP/1.1 pipelines in favor of a + * highly optimized, reactive, native interceptor tailored for HTTP/2 multiplexing and trailing + * headers. + * + *

Usage

+ * + *

gRPC requires HTTP/2. Ensure your Jooby application is configured to use a supported server + * with HTTP/2 enabled. + * + *

{@code
+ * import io.jooby.Jooby;
+ * import io.jooby.ServerOptions;
+ * import io.jooby.grpc.GrpcModule;
+ * * public class App extends Jooby {
+ * {
+ * setServerOptions(new ServerOptions().setHttp2(true).setSecurePort(8443));
+ * * // Install the extension and register your services
+ * install(new GrpcModule(new GreeterService()));
+ * }
+ * }
+ * }
+ * + *

Dependency Injection

+ * + *

If your gRPC services require external dependencies (like repositories or configuration), you + * can register the service classes instead of instances. The module will automatically provision + * them using Jooby's DI registry (e.g., Guice, Spring) during the application startup phase. + * + *

{@code
+ * public class App extends Jooby {
+ * {
+ * install(new GuiceModule());
+ * * // Pass the class reference. Guice will instantiate it!
+ * install(new GrpcModule(GreeterService.class));
+ * }
+ * }
+ * }
+ * + * * + * + *

Note: gRPC services are inherently registered as Singletons. Ensure your + * service implementations are thread-safe and do not hold request-scoped state in instance + * variables. + * + *

Logging

+ * + *

gRPC internally uses {@code java.util.logging}. This module automatically installs the {@link + * SLF4JBridgeHandler} to redirect all internal gRPC logs to your configured SLF4J backend. + */ module io.jooby.grpc { exports io.jooby.grpc; diff --git a/modules/jooby-gson/pom.xml b/modules/jooby-gson/pom.xml index 9c5ec923f9..f00409eda8 100644 --- a/modules/jooby-gson/pom.xml +++ b/modules/jooby-gson/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-gson jooby-gson diff --git a/modules/jooby-guice/pom.xml b/modules/jooby-guice/pom.xml index c30267bdaa..d6f5b11fe5 100644 --- a/modules/jooby-guice/pom.xml +++ b/modules/jooby-guice/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-guice jooby-guice diff --git a/modules/jooby-handlebars/pom.xml b/modules/jooby-handlebars/pom.xml index e11fc7ec02..0c3c442b35 100644 --- a/modules/jooby-handlebars/pom.xml +++ b/modules/jooby-handlebars/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-handlebars jooby-handlebars diff --git a/modules/jooby-hibernate-validator/pom.xml b/modules/jooby-hibernate-validator/pom.xml index 322330f2ac..4e34f44cc9 100644 --- a/modules/jooby-hibernate-validator/pom.xml +++ b/modules/jooby-hibernate-validator/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-hibernate-validator jooby-hibernate-validator diff --git a/modules/jooby-hibernate/pom.xml b/modules/jooby-hibernate/pom.xml index 8aa7be4727..4f82dfc667 100644 --- a/modules/jooby-hibernate/pom.xml +++ b/modules/jooby-hibernate/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-hibernate jooby-hibernate diff --git a/modules/jooby-hikari/pom.xml b/modules/jooby-hikari/pom.xml index f636505f72..13516e80fb 100644 --- a/modules/jooby-hikari/pom.xml +++ b/modules/jooby-hikari/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-hikari jooby-hikari diff --git a/modules/jooby-jackson/pom.xml b/modules/jooby-jackson/pom.xml index 63e25177f5..b173312984 100644 --- a/modules/jooby-jackson/pom.xml +++ b/modules/jooby-jackson/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-jackson jooby-jackson diff --git a/modules/jooby-jackson/src/main/java/io/jooby/internal/jackson/JacksonProjectedSerializer.java b/modules/jooby-jackson/src/main/java/io/jooby/internal/jackson/JacksonProjectedSerializer.java index ba3158877c..87d300457a 100644 --- a/modules/jooby-jackson/src/main/java/io/jooby/internal/jackson/JacksonProjectedSerializer.java +++ b/modules/jooby-jackson/src/main/java/io/jooby/internal/jackson/JacksonProjectedSerializer.java @@ -17,7 +17,7 @@ import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider; import io.jooby.Projected; import io.jooby.Projection; -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; public class JacksonProjectedSerializer extends JsonSerializer { private final Map, ObjectWriter> writerCache = new ConcurrentHashMap<>(); @@ -39,7 +39,7 @@ public void serialize( p -> { var filters = new SimpleFilterProvider() - .addFilter(JacksonModule.FILTER_ID, new JacksonProjectionFilter(p)); + .addFilter(Jackson2Module.FILTER_ID, new JacksonProjectionFilter(p)); return mapper.writer(filters); }); diff --git a/modules/jooby-jackson/src/main/java/io/jooby/jackson/Jackson2Module.java b/modules/jooby-jackson/src/main/java/io/jooby/jackson/Jackson2Module.java new file mode 100644 index 0000000000..0a53e685ff --- /dev/null +++ b/modules/jooby-jackson/src/main/java/io/jooby/jackson/Jackson2Module.java @@ -0,0 +1,231 @@ +/* + * Jooby https://jooby.io + * Apache License Version 2.0 https://jooby.io/LICENSE.txt + * Copyright 2014 Edgar Espina + */ +package io.jooby.jackson; + +import java.io.InputStream; +import java.lang.reflect.Type; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Stream; + +import com.fasterxml.jackson.annotation.JsonFilter; +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.Module; +import com.fasterxml.jackson.databind.exc.MismatchedInputException; +import com.fasterxml.jackson.databind.json.JsonMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider; +import com.fasterxml.jackson.databind.type.TypeFactory; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.fasterxml.jackson.module.paramnames.ParameterNamesModule; +import edu.umd.cs.findbugs.annotations.NonNull; +import io.jooby.*; +import io.jooby.internal.jackson.*; +import io.jooby.output.Output; + +/** + * JSON module using Jackson: https://jooby.io/modules/jackson2. + * + *

Usage: + * + *

{@code
+ * {
+ *
+ *   install(new Jackson2Module());
+ *
+ *   get("/", ctx -> {
+ *     MyObject myObject = ...;
+ *     // send json
+ *     return myObject;
+ *   });
+ *
+ *   post("/", ctx -> {
+ *     // read json
+ *     MyObject myObject = ctx.body(MyObject.class);
+ *     // send json
+ *     return myObject;
+ *   });
+ * }
+ * }
+ * + * For body decoding the client must specify the Content-Type header set to + * application/json. + * + *

You can retrieve the {@link ObjectMapper} via require call: + * + *

{@code
+ * {
+ *
+ *   ObjectMapper mapper = require(ObjectMapper.class);
+ *
+ * }
+ * }
+ * + * Complete documentation is available at: https://jooby.io/modules/jackson2. + * + * @author edgar + * @since 2.0.0 + */ +public class Jackson2Module implements Extension, MessageDecoder, MessageEncoder { + public static final String FILTER_ID = "jooby.projection"; + + // Cache for ObjectWriters tied to specific projection strings + private final Map writerCache = new ConcurrentHashMap<>(); + + @JsonFilter(FILTER_ID) + private interface ProjectionMixIn {} + + private final MediaType mediaType; + + private final ObjectMapper mapper; + + private final TypeFactory typeFactory; + + private final Set> modules = new HashSet<>(); + + private static final Map defaultTypes = new HashMap<>(); + + static { + defaultTypes.put("XmlMapper", MediaType.xml); + } + + /** + * Creates a Jackson module. + * + * @param mapper Object mapper to use. + * @param contentType Content type. + */ + public Jackson2Module(@NonNull ObjectMapper mapper, @NonNull MediaType contentType) { + this.mapper = mapper; + this.typeFactory = mapper.getTypeFactory(); + this.mediaType = contentType; + } + + /** + * Creates a Jackson module. + * + * @param mapper Object mapper to use. + */ + public Jackson2Module(@NonNull ObjectMapper mapper) { + this(mapper, defaultTypes.getOrDefault(mapper.getClass().getSimpleName(), MediaType.json)); + } + + /** Creates a Jackson module using the default object mapper from {@link #create(Module...)}. */ + public Jackson2Module() { + this(create()); + } + + /** + * Add a Jackson module to the object mapper. This method require a dependency injection framework + * which is responsible for provisioning a module instance. + * + * @param module Module type. + * @return This module. + */ + public Jackson2Module module(Class module) { + modules.add(module); + return this; + } + + @Override + 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); + + // Parsing exception as 400 + application.errorCode(JsonParseException.class, StatusCode.BAD_REQUEST); + application.errorCode(MismatchedInputException.class, StatusCode.BAD_REQUEST); + + // Filter + var defaultProvider = new SimpleFilterProvider().setFailOnUnknownId(false); + mapper.addMixIn(Object.class, ProjectionMixIn.class); + mapper.setFilterProvider(defaultProvider); + var projectionModule = new SimpleModule(); + projectionModule.addSerializer(Projected.class, new JacksonProjectedSerializer(mapper)); + mapper.registerModule(projectionModule); + + application.onStarting( + () -> { + for (Class type : modules) { + 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); + } + } + }); + } + + @Override + public Output encode(@NonNull Context ctx, @NonNull Object value) throws Exception { + var factory = ctx.getOutputFactory(); + ctx.setDefaultResponseType(mediaType); + if (value instanceof Projected projected) { + var p = projected.getProjection(); + var writer = + writerCache.computeIfAbsent( + p.getType().getName() + p.toView(), + k -> { + // Use a specialized ObjectWriter with our custom path filter + var filters = + new SimpleFilterProvider().addFilter(FILTER_ID, new JacksonProjectionFilter(p)); + return mapper.writer(filters); + }); + return factory.wrap(writer.writeValueAsBytes(projected.getValue())); + } + // let jackson uses his own cache, so wrap the bytes + return factory.wrap(mapper.writeValueAsBytes(value)); + } + + @Override + public Object decode(Context ctx, Type type) throws Exception { + Body body = ctx.body(); + if (body.isInMemory()) { + if (type == JsonNode.class) { + return mapper.readTree(body.bytes()); + } + return mapper.readValue(body.bytes(), typeFactory.constructType(type)); + } else { + try (InputStream stream = body.stream()) { + if (type == JsonNode.class) { + return mapper.readTree(stream); + } + return mapper.readValue(stream, typeFactory.constructType(type)); + } + } + } + + /** + * Default object mapper. Install {@link Jdk8Module}, {@link JavaTimeModule}, {@link + * ParameterNamesModule}. + * + * @param modules Extra/additional modules to install. + * @return Object mapper instance. + */ + public static ObjectMapper create(Module... modules) { + JsonMapper.Builder builder = + JsonMapper.builder() + .addModule(new ParameterNamesModule()) + .addModule(new Jdk8Module()) + .addModule(new JavaTimeModule()) + .findAndAddModules(); + + Stream.of(modules).forEach(builder::addModule); + + return builder.build(); + } +} 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..0e21925126 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 @@ -5,37 +5,13 @@ */ package io.jooby.jackson; -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.concurrent.ConcurrentHashMap; -import java.util.stream.Stream; - -import com.fasterxml.jackson.annotation.JsonFilter; -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.Module; -import com.fasterxml.jackson.databind.exc.MismatchedInputException; -import com.fasterxml.jackson.databind.json.JsonMapper; -import com.fasterxml.jackson.databind.module.SimpleModule; -import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider; -import com.fasterxml.jackson.databind.type.TypeFactory; +import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.fasterxml.jackson.module.paramnames.ParameterNamesModule; import edu.umd.cs.findbugs.annotations.NonNull; -import io.jooby.*; -import io.jooby.internal.jackson.*; -import io.jooby.output.Output; -import io.jooby.rpc.jsonrpc.JsonRpcErrorCode; -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; +import io.jooby.MediaType; /** * JSON module using Jackson: https://jooby.io/modules/jackson2. @@ -79,40 +55,13 @@ * * @author edgar * @since 2.0.0 + * @deprecated Use {@link io.jooby.jackson.JacksonModule} instead. */ -public class JacksonModule implements Extension, MessageDecoder, MessageEncoder { - public static final String FILTER_ID = "jooby.projection"; - - // Cache for ObjectWriters tied to specific projection strings - private final Map writerCache = new ConcurrentHashMap<>(); - - @JsonFilter(FILTER_ID) - private interface ProjectionMixIn {} - - private final MediaType mediaType; - - private final ObjectMapper mapper; +@Deprecated(since = "4.3.0", forRemoval = true) +public class JacksonModule extends Jackson2Module { - private final TypeFactory typeFactory; - - private final Set> modules = new HashSet<>(); - - private static final Map defaultTypes = new HashMap<>(); - - static { - defaultTypes.put("XmlMapper", MediaType.xml); - } - - /** - * Creates a Jackson module. - * - * @param mapper Object mapper to use. - * @param contentType Content type. - */ public JacksonModule(@NonNull ObjectMapper mapper, @NonNull MediaType contentType) { - this.mapper = mapper; - this.typeFactory = mapper.getTypeFactory(); - this.mediaType = contentType; + super(mapper, contentType); } /** @@ -121,104 +70,12 @@ public JacksonModule(@NonNull ObjectMapper mapper, @NonNull MediaType contentTyp * @param mapper Object mapper to use. */ public JacksonModule(@NonNull ObjectMapper mapper) { - this(mapper, defaultTypes.getOrDefault(mapper.getClass().getSimpleName(), MediaType.json)); + super(mapper); } /** Creates a Jackson module using the default object mapper from {@link #create(Module...)}. */ public JacksonModule() { - this(create()); - } - - /** - * Add a Jackson module to the object mapper. This method require a dependency injection framework - * which is responsible for provisioning a module instance. - * - * @param module Module type. - * @return This module. - */ - public JacksonModule module(Class module) { - modules.add(module); - return this; - } - - @Override - 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); - - // Parsing exception as 400 - 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 - .mapOf(Class.class, JsonRpcErrorCode.class) - .put(MismatchedInputException.class, JsonRpcErrorCode.INVALID_PARAMS) - .put(DatabindException.class, JsonRpcErrorCode.INVALID_PARAMS); - - // Filter - var defaultProvider = new SimpleFilterProvider().setFailOnUnknownId(false); - mapper.addMixIn(Object.class, ProjectionMixIn.class); - mapper.setFilterProvider(defaultProvider); - var projectionModule = new SimpleModule(); - projectionModule.addSerializer(Projected.class, new JacksonProjectedSerializer(mapper)); - mapper.registerModule(projectionModule); - - application.onStarting( - () -> { - for (Class type : modules) { - Module module = application.require(type); - mapper.registerModule(module); - } - }); - } - - @Override - public Output encode(@NonNull Context ctx, @NonNull Object value) throws Exception { - var factory = ctx.getOutputFactory(); - ctx.setDefaultResponseType(mediaType); - if (value instanceof Projected projected) { - var p = projected.getProjection(); - var writer = - writerCache.computeIfAbsent( - p.getType().getName() + p.toView(), - k -> { - // Use a specialized ObjectWriter with our custom path filter - var filters = - new SimpleFilterProvider().addFilter(FILTER_ID, new JacksonProjectionFilter(p)); - return mapper.writer(filters); - }); - return factory.wrap(writer.writeValueAsBytes(projected.getValue())); - } - // let jackson uses his own cache, so wrap the bytes - return factory.wrap(mapper.writeValueAsBytes(value)); - } - - @Override - public Object decode(Context ctx, Type type) throws Exception { - Body body = ctx.body(); - if (body.isInMemory()) { - if (type == JsonNode.class) { - return mapper.readTree(body.bytes()); - } - return mapper.readValue(body.bytes(), typeFactory.constructType(type)); - } else { - try (InputStream stream = body.stream()) { - if (type == JsonNode.class) { - return mapper.readTree(stream); - } - return mapper.readValue(stream, typeFactory.constructType(type)); - } - } + super(create()); } /** @@ -229,20 +86,6 @@ public Object decode(Context ctx, Type type) throws Exception { * @return Object mapper instance. */ public static ObjectMapper create(Module... modules) { - JsonMapper.Builder builder = - JsonMapper.builder() - .addModule(new ParameterNamesModule()) - .addModule(new Jdk8Module()) - .addModule(new JavaTimeModule()); - - 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); - - return builder.build(); + return Jackson2Module.create(modules); } } diff --git a/modules/jooby-jackson/src/main/java/io/jooby/jackson/package-info.java b/modules/jooby-jackson/src/main/java/io/jooby/jackson/package-info.java index 12468e3123..50c4576c91 100644 --- a/modules/jooby-jackson/src/main/java/io/jooby/jackson/package-info.java +++ b/modules/jooby-jackson/src/main/java/io/jooby/jackson/package-info.java @@ -1,2 +1,45 @@ +/** + * JSON module using Jackson: https://jooby.io/modules/jackson2. + * + *

Usage: + * + *

{@code
+ * {
+ *
+ *   install(new Jackson2Module());
+ *
+ *   get("/", ctx -> {
+ *     MyObject myObject = ...;
+ *     // send json
+ *     return myObject;
+ *   });
+ *
+ *   post("/", ctx -> {
+ *     // read json
+ *     MyObject myObject = ctx.body(MyObject.class);
+ *     // send json
+ *     return myObject;
+ *   });
+ * }
+ * }
+ * + * For body decoding the client must specify the Content-Type header set to + * application/json. + * + *

You can retrieve the {@link com.fasterxml.jackson.databind.ObjectMapper} via require call: + * + *

{@code
+ * {
+ *
+ *   ObjectMapper mapper = require(ObjectMapper.class);
+ *
+ * }
+ * }
+ * + * Complete documentation is available at: https://jooby.io/modules/jackson2. + * + * @author edgar + * @since 2.0.0 + */ @edu.umd.cs.findbugs.annotations.ReturnValuesAreNonnullByDefault package io.jooby.jackson; diff --git a/modules/jooby-jackson/src/main/java/module-info.java b/modules/jooby-jackson/src/main/java/module-info.java index f66c8fa145..018fb55d15 100644 --- a/modules/jooby-jackson/src/main/java/module-info.java +++ b/modules/jooby-jackson/src/main/java/module-info.java @@ -3,7 +3,52 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -/** Jackson module. */ + +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * JSON module using Jackson: https://jooby.io/modules/jackson2. + * + *

Usage: + * + *

{@code
+ * {
+ *
+ *   install(new Jackson2Module());
+ *
+ *   get("/", ctx -> {
+ *     MyObject myObject = ...;
+ *     // send json
+ *     return myObject;
+ *   });
+ *
+ *   post("/", ctx -> {
+ *     // read json
+ *     MyObject myObject = ctx.body(MyObject.class);
+ *     // send json
+ *     return myObject;
+ *   });
+ * }
+ * }
+ * + * For body decoding the client must specify the Content-Type header set to + * application/json. + * + *

You can retrieve the {@link ObjectMapper} via require call: + * + *

{@code
+ * {
+ *
+ *   ObjectMapper mapper = require(ObjectMapper.class);
+ *
+ * }
+ * }
+ * + * Complete documentation is available at: https://jooby.io/modules/jackson2. + * + * @author edgar + * @since 2.0.0 + */ module io.jooby.jackson { exports io.jooby.jackson; diff --git a/modules/jooby-jackson/src/test/java/io/jooby/jackson/JacksonJsonModuleTest.java b/modules/jooby-jackson/src/test/java/io/jooby/jackson/JacksonJsonModuleTest.java index e4bf60dac4..39a397d8ec 100644 --- a/modules/jooby-jackson/src/test/java/io/jooby/jackson/JacksonJsonModuleTest.java +++ b/modules/jooby-jackson/src/test/java/io/jooby/jackson/JacksonJsonModuleTest.java @@ -31,7 +31,7 @@ public void renderJson() throws Exception { Context ctx = mock(Context.class); when(ctx.getOutputFactory()).thenReturn(OutputFactory.create(OutputOptions.small())); - JacksonModule jackson = new JacksonModule(new ObjectMapper()); + Jackson2Module jackson = new Jackson2Module(new ObjectMapper()); var buffer = jackson.encode(ctx, mapOf("k", "v")); assertEquals("{\"k\":\"v\"}", StandardCharsets.UTF_8.decode(buffer.asByteBuffer()).toString()); @@ -49,7 +49,7 @@ public void parseJson() throws Exception { Context ctx = mock(Context.class); when(ctx.body()).thenReturn(body); - JacksonModule jackson = new JacksonModule(new ObjectMapper()); + Jackson2Module jackson = new Jackson2Module(new ObjectMapper()); Map result = (Map) jackson.decode(ctx, Map.class); assertEquals(mapOf("k", "v"), result); @@ -60,7 +60,7 @@ public void renderXml() throws Exception { Context ctx = mock(Context.class); when(ctx.getOutputFactory()).thenReturn(OutputFactory.create(OutputOptions.small())); - JacksonModule jackson = new JacksonModule(new XmlMapper()); + Jackson2Module jackson = new Jackson2Module(new XmlMapper()); var buffer = jackson.encode(ctx, mapOf("k", "v")); assertEquals( @@ -80,7 +80,7 @@ public void parseXml() throws Exception { Context ctx = mock(Context.class); when(ctx.body()).thenReturn(body); - JacksonModule jackson = new JacksonModule(new XmlMapper()); + Jackson2Module jackson = new Jackson2Module(new XmlMapper()); Map result = (Map) jackson.decode(ctx, Map.class); assertEquals(mapOf("k", "v"), result); diff --git a/modules/jooby-jackson3/pom.xml b/modules/jooby-jackson3/pom.xml index 5f3d755e58..266db1b7a1 100644 --- a/modules/jooby-jackson3/pom.xml +++ b/modules/jooby-jackson3/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-jackson3 jooby-jackson3 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..f5253e7b0e 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; @@ -19,18 +16,9 @@ import io.jooby.*; import io.jooby.internal.jackson3.*; import io.jooby.output.Output; -import io.jooby.rpc.jsonrpc.JsonRpcErrorCode; -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; import tools.jackson.databind.json.JsonMapper; -import tools.jackson.databind.module.SimpleModule; import tools.jackson.databind.ser.std.SimpleFilterProvider; import tools.jackson.databind.type.TypeFactory; @@ -84,7 +72,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,55 +127,54 @@ 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); - - // JSON-RPC - services.put(JsonRpcParser.class, new JacksonJsonRpcParser(mapper)); - services - .mapOf(Class.class, JsonRpcErrorCode.class) - .put(StreamReadException.class, JsonRpcErrorCode.INVALID_PARAMS) - .put(MismatchedInputException.class, JsonRpcErrorCode.INVALID_PARAMS) - .put(DatabindException.class, JsonRpcErrorCode.INVALID_PARAMS); + var services = application.getServices(); + bindMapper(services, mapper); // Parsing exception as 400 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 @@ -237,14 +224,9 @@ public Object decode(Context ctx, Type type) throws Exception { * @return Object mapper instance. */ public static JsonMapper create(JacksonModule... modules) { - JsonMapper.Builder builder = JsonMapper.builder(); + JsonMapper.Builder builder = JsonMapper.builder().findAndAddModules(); 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); return builder.build(); } diff --git a/modules/jooby-jasypt/pom.xml b/modules/jooby-jasypt/pom.xml index d5656f160b..ea7174963f 100644 --- a/modules/jooby-jasypt/pom.xml +++ b/modules/jooby-jasypt/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-jasypt jooby-jasypt diff --git a/modules/jooby-javadoc/pom.xml b/modules/jooby-javadoc/pom.xml index a61504aa84..6063eaab96 100644 --- a/modules/jooby-javadoc/pom.xml +++ b/modules/jooby-javadoc/pom.xml @@ -8,7 +8,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-javadoc jooby-javadoc diff --git a/modules/jooby-jdbi/pom.xml b/modules/jooby-jdbi/pom.xml index 76ecc0f8d2..8c2d7c2f83 100644 --- a/modules/jooby-jdbi/pom.xml +++ b/modules/jooby-jdbi/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-jdbi jooby-jdbi diff --git a/modules/jooby-jetty/pom.xml b/modules/jooby-jetty/pom.xml index d55c9a17af..3a1f0a43ef 100644 --- a/modules/jooby-jetty/pom.xml +++ b/modules/jooby-jetty/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-jetty jooby-jetty diff --git a/modules/jooby-jsonrpc-avaje-jsonb/pom.xml b/modules/jooby-jsonrpc-avaje-jsonb/pom.xml new file mode 100644 index 0000000000..2d4658e568 --- /dev/null +++ b/modules/jooby-jsonrpc-avaje-jsonb/pom.xml @@ -0,0 +1,34 @@ + + + 4.0.0 + + io.jooby + modules + 4.3.0 + + + jooby-jsonrpc-avaje-jsonb + jooby-jsonrpc-avaje-jsonb + + + + io.jooby + jooby-jsonrpc + ${jooby.version} + + + + io.jooby + jooby-avaje-jsonb + ${jooby.version} + + + + tools.jackson.core + jackson-databind + + + + diff --git a/modules/jooby-avaje-jsonb/src/main/java/io/jooby/internal/avaje/jsonb/AvajeJsonRpcDecoder.java b/modules/jooby-jsonrpc-avaje-jsonb/src/main/java/io/jooby/internal/jsonrpc/avaje/jsonb/AvajeJsonRpcDecoder.java similarity index 92% rename from modules/jooby-avaje-jsonb/src/main/java/io/jooby/internal/avaje/jsonb/AvajeJsonRpcDecoder.java rename to modules/jooby-jsonrpc-avaje-jsonb/src/main/java/io/jooby/internal/jsonrpc/avaje/jsonb/AvajeJsonRpcDecoder.java index 354270f049..961cf72f45 100644 --- a/modules/jooby-avaje-jsonb/src/main/java/io/jooby/internal/avaje/jsonb/AvajeJsonRpcDecoder.java +++ b/modules/jooby-jsonrpc-avaje-jsonb/src/main/java/io/jooby/internal/jsonrpc/avaje/jsonb/AvajeJsonRpcDecoder.java @@ -3,7 +3,7 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.internal.avaje.jsonb; +package io.jooby.internal.jsonrpc.avaje.jsonb; import java.lang.reflect.Type; @@ -11,7 +11,7 @@ import io.avaje.jsonb.Jsonb; import io.jooby.exception.MissingValueException; import io.jooby.exception.TypeMismatchException; -import io.jooby.rpc.jsonrpc.JsonRpcDecoder; +import io.jooby.jsonrpc.JsonRpcDecoder; public class AvajeJsonRpcDecoder implements JsonRpcDecoder { diff --git a/modules/jooby-avaje-jsonb/src/main/java/io/jooby/internal/avaje/jsonb/AvajeJsonRpcErrorAdapter.java b/modules/jooby-jsonrpc-avaje-jsonb/src/main/java/io/jooby/internal/jsonrpc/avaje/jsonb/AvajeJsonRpcErrorAdapter.java similarity index 71% rename from modules/jooby-avaje-jsonb/src/main/java/io/jooby/internal/avaje/jsonb/AvajeJsonRpcErrorAdapter.java rename to modules/jooby-jsonrpc-avaje-jsonb/src/main/java/io/jooby/internal/jsonrpc/avaje/jsonb/AvajeJsonRpcErrorAdapter.java index 0f239fd5ed..1979db2d45 100644 --- a/modules/jooby-avaje-jsonb/src/main/java/io/jooby/internal/avaje/jsonb/AvajeJsonRpcErrorAdapter.java +++ b/modules/jooby-jsonrpc-avaje-jsonb/src/main/java/io/jooby/internal/jsonrpc/avaje/jsonb/AvajeJsonRpcErrorAdapter.java @@ -3,15 +3,15 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.internal.avaje.jsonb; +package io.jooby.internal.jsonrpc.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.jsonrpc.JsonRpcResponse.ErrorDetail; +import io.jooby.jsonrpc.JsonRpcResponse; -public class AvajeJsonRpcErrorAdapter implements JsonAdapter { +public class AvajeJsonRpcErrorAdapter implements JsonAdapter { private final Jsonb jsonb; @@ -20,7 +20,7 @@ public AvajeJsonRpcErrorAdapter(Jsonb jsonb) { } @Override - public void toJson(JsonWriter writer, ErrorDetail error) { + public void toJson(JsonWriter writer, JsonRpcResponse.ErrorDetail error) { writer.beginObject(); writer.name("code"); @@ -38,7 +38,7 @@ public void toJson(JsonWriter writer, ErrorDetail error) { } @Override - public ErrorDetail fromJson(JsonReader reader) { + public JsonRpcResponse.ErrorDetail fromJson(JsonReader reader) { throw new UnsupportedOperationException("Servers don't deserialize error responses"); } } diff --git a/modules/jooby-avaje-jsonb/src/main/java/io/jooby/internal/avaje/jsonb/AvajeJsonRpcParser.java b/modules/jooby-jsonrpc-avaje-jsonb/src/main/java/io/jooby/internal/jsonrpc/avaje/jsonb/AvajeJsonRpcParser.java similarity index 79% rename from modules/jooby-avaje-jsonb/src/main/java/io/jooby/internal/avaje/jsonb/AvajeJsonRpcParser.java rename to modules/jooby-jsonrpc-avaje-jsonb/src/main/java/io/jooby/internal/jsonrpc/avaje/jsonb/AvajeJsonRpcParser.java index 683967005a..6f12ee0e1c 100644 --- a/modules/jooby-avaje-jsonb/src/main/java/io/jooby/internal/avaje/jsonb/AvajeJsonRpcParser.java +++ b/modules/jooby-jsonrpc-avaje-jsonb/src/main/java/io/jooby/internal/jsonrpc/avaje/jsonb/AvajeJsonRpcParser.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.jsonrpc.avaje.jsonb; import java.lang.reflect.Type; import io.avaje.jsonb.Jsonb; -import io.jooby.rpc.jsonrpc.JsonRpcDecoder; -import io.jooby.rpc.jsonrpc.JsonRpcParser; -import io.jooby.rpc.jsonrpc.JsonRpcReader; +import io.jooby.jsonrpc.JsonRpcDecoder; +import io.jooby.jsonrpc.JsonRpcParser; +import io.jooby.jsonrpc.JsonRpcReader; public class AvajeJsonRpcParser implements JsonRpcParser { diff --git a/modules/jooby-avaje-jsonb/src/main/java/io/jooby/internal/avaje/jsonb/AvajeJsonRpcReader.java b/modules/jooby-jsonrpc-avaje-jsonb/src/main/java/io/jooby/internal/jsonrpc/avaje/jsonb/AvajeJsonRpcReader.java similarity index 95% rename from modules/jooby-avaje-jsonb/src/main/java/io/jooby/internal/avaje/jsonb/AvajeJsonRpcReader.java rename to modules/jooby-jsonrpc-avaje-jsonb/src/main/java/io/jooby/internal/jsonrpc/avaje/jsonb/AvajeJsonRpcReader.java index 332d303af4..4c79a4e2ef 100644 --- a/modules/jooby-avaje-jsonb/src/main/java/io/jooby/internal/avaje/jsonb/AvajeJsonRpcReader.java +++ b/modules/jooby-jsonrpc-avaje-jsonb/src/main/java/io/jooby/internal/jsonrpc/avaje/jsonb/AvajeJsonRpcReader.java @@ -3,15 +3,15 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.internal.avaje.jsonb; +package io.jooby.internal.jsonrpc.avaje.jsonb; import java.util.List; import java.util.Map; import io.jooby.exception.MissingValueException; import io.jooby.exception.TypeMismatchException; -import io.jooby.rpc.jsonrpc.JsonRpcDecoder; -import io.jooby.rpc.jsonrpc.JsonRpcReader; +import io.jooby.jsonrpc.JsonRpcDecoder; +import io.jooby.jsonrpc.JsonRpcReader; public class AvajeJsonRpcReader implements JsonRpcReader { diff --git a/modules/jooby-avaje-jsonb/src/main/java/io/jooby/internal/avaje/jsonb/AvajeJsonRpcRequestAdapter.java b/modules/jooby-jsonrpc-avaje-jsonb/src/main/java/io/jooby/internal/jsonrpc/avaje/jsonb/AvajeJsonRpcRequestAdapter.java similarity index 96% rename from modules/jooby-avaje-jsonb/src/main/java/io/jooby/internal/avaje/jsonb/AvajeJsonRpcRequestAdapter.java rename to modules/jooby-jsonrpc-avaje-jsonb/src/main/java/io/jooby/internal/jsonrpc/avaje/jsonb/AvajeJsonRpcRequestAdapter.java index d4db2c8480..e37d9f2ff8 100644 --- a/modules/jooby-avaje-jsonb/src/main/java/io/jooby/internal/avaje/jsonb/AvajeJsonRpcRequestAdapter.java +++ b/modules/jooby-jsonrpc-avaje-jsonb/src/main/java/io/jooby/internal/jsonrpc/avaje/jsonb/AvajeJsonRpcRequestAdapter.java @@ -3,7 +3,7 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.internal.avaje.jsonb; +package io.jooby.internal.jsonrpc.avaje.jsonb; import java.util.List; import java.util.Map; @@ -13,7 +13,7 @@ import io.avaje.json.JsonWriter; import io.avaje.jsonb.JsonType; import io.avaje.jsonb.Jsonb; -import io.jooby.rpc.jsonrpc.JsonRpcRequest; +import io.jooby.jsonrpc.JsonRpcRequest; public class AvajeJsonRpcRequestAdapter implements JsonAdapter { diff --git a/modules/jooby-avaje-jsonb/src/main/java/io/jooby/internal/avaje/jsonb/AvajeJsonRpcResponseAdapter.java b/modules/jooby-jsonrpc-avaje-jsonb/src/main/java/io/jooby/internal/jsonrpc/avaje/jsonb/AvajeJsonRpcResponseAdapter.java similarity index 93% rename from modules/jooby-avaje-jsonb/src/main/java/io/jooby/internal/avaje/jsonb/AvajeJsonRpcResponseAdapter.java rename to modules/jooby-jsonrpc-avaje-jsonb/src/main/java/io/jooby/internal/jsonrpc/avaje/jsonb/AvajeJsonRpcResponseAdapter.java index f696b91143..9ff827c5fa 100644 --- a/modules/jooby-avaje-jsonb/src/main/java/io/jooby/internal/avaje/jsonb/AvajeJsonRpcResponseAdapter.java +++ b/modules/jooby-jsonrpc-avaje-jsonb/src/main/java/io/jooby/internal/jsonrpc/avaje/jsonb/AvajeJsonRpcResponseAdapter.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.jsonrpc.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.jsonrpc.JsonRpcResponse; +import io.jooby.jsonrpc.JsonRpcResponse; public class AvajeJsonRpcResponseAdapter implements JsonAdapter { diff --git a/modules/jooby-jsonrpc-avaje-jsonb/src/main/java/io/jooby/jsonrpc/avaje/jsonb/JsonRpcAvajeJsonbModule.java b/modules/jooby-jsonrpc-avaje-jsonb/src/main/java/io/jooby/jsonrpc/avaje/jsonb/JsonRpcAvajeJsonbModule.java new file mode 100644 index 0000000000..2a2a3c0810 --- /dev/null +++ b/modules/jooby-jsonrpc-avaje-jsonb/src/main/java/io/jooby/jsonrpc/avaje/jsonb/JsonRpcAvajeJsonbModule.java @@ -0,0 +1,23 @@ +/* + * Jooby https://jooby.io + * Apache License Version 2.0 https://jooby.io/LICENSE.txt + * Copyright 2014 Edgar Espina + */ +package io.jooby.jsonrpc.avaje.jsonb; + +import edu.umd.cs.findbugs.annotations.NonNull; +import io.avaje.jsonb.Jsonb; +import io.jooby.Extension; +import io.jooby.Jooby; +import io.jooby.internal.jsonrpc.avaje.jsonb.AvajeJsonRpcParser; +import io.jooby.jsonrpc.JsonRpcParser; + +public class JsonRpcAvajeJsonbModule implements Extension { + @Override + public void install(@NonNull Jooby application) throws Exception { + // JSON-RPC + application + .getServices() + .put(JsonRpcParser.class, new AvajeJsonRpcParser(application.require(Jsonb.class))); + } +} diff --git a/modules/jooby-jsonrpc-avaje-jsonb/src/main/java/io/jooby/jsonrpc/avaje/jsonb/JsonRpcExtension.java b/modules/jooby-jsonrpc-avaje-jsonb/src/main/java/io/jooby/jsonrpc/avaje/jsonb/JsonRpcExtension.java new file mode 100644 index 0000000000..cb20cb6dbf --- /dev/null +++ b/modules/jooby-jsonrpc-avaje-jsonb/src/main/java/io/jooby/jsonrpc/avaje/jsonb/JsonRpcExtension.java @@ -0,0 +1,23 @@ +/* + * Jooby https://jooby.io + * Apache License Version 2.0 https://jooby.io/LICENSE.txt + * Copyright 2014 Edgar Espina + */ +package io.jooby.jsonrpc.avaje.jsonb; + +import io.avaje.jsonb.Jsonb; +import io.avaje.jsonb.spi.JsonbComponent; +import io.jooby.internal.jsonrpc.avaje.jsonb.AvajeJsonRpcErrorAdapter; +import io.jooby.internal.jsonrpc.avaje.jsonb.AvajeJsonRpcRequestAdapter; +import io.jooby.internal.jsonrpc.avaje.jsonb.AvajeJsonRpcResponseAdapter; +import io.jooby.jsonrpc.JsonRpcRequest; +import io.jooby.jsonrpc.JsonRpcResponse; + +public class JsonRpcExtension implements JsonbComponent { + @Override + public void register(Jsonb.Builder jsonb) { + jsonb.add(JsonRpcRequest.class, AvajeJsonRpcRequestAdapter::new); + jsonb.add(JsonRpcResponse.class, AvajeJsonRpcResponseAdapter::new); + jsonb.add(JsonRpcResponse.ErrorDetail.class, AvajeJsonRpcErrorAdapter::new); + } +} diff --git a/modules/jooby-jsonrpc-avaje-jsonb/src/main/java/module-info.java b/modules/jooby-jsonrpc-avaje-jsonb/src/main/java/module-info.java new file mode 100644 index 0000000000..860680b0a4 --- /dev/null +++ b/modules/jooby-jsonrpc-avaje-jsonb/src/main/java/module-info.java @@ -0,0 +1,30 @@ +/** + * Implementation of jooby-jsonrpc using avaje-jsonb. It provides the parser, decoder, reader, and + * serializer. + * + *

Usage: + * + *

{@code
+ * {
+ *   install(new AvajeJsonbModule());
+ *   install(new JsonRpcAvajeJsonbModule());
+ *   install(new JsonRpcModule());
+ * }
+ * }
+ * + * @since 4.3.0 + * @author edgar + */ +module io.jooby.jsonrpc.avaje.jsonb { + exports io.jooby.jsonrpc.avaje.jsonb; + + provides io.avaje.jsonb.spi.JsonbComponent with + io.jooby.jsonrpc.avaje.jsonb.JsonRpcExtension; + + requires io.jooby; + requires io.jooby.jsonrpc; + requires static com.github.spotbugs.annotations; + requires typesafe.config; + requires org.slf4j; + requires io.avaje.jsonb; +} diff --git a/modules/jooby-jsonrpc-avaje-jsonb/src/main/resources/META-INF/services/io.avaje.jsonb.spi.JsonbExtension b/modules/jooby-jsonrpc-avaje-jsonb/src/main/resources/META-INF/services/io.avaje.jsonb.spi.JsonbExtension new file mode 100644 index 0000000000..caf8a344f1 --- /dev/null +++ b/modules/jooby-jsonrpc-avaje-jsonb/src/main/resources/META-INF/services/io.avaje.jsonb.spi.JsonbExtension @@ -0,0 +1 @@ +io.jooby.jsonrpc.avaje.jsonb.JsonRpcExtension diff --git a/modules/jooby-jsonrpc-jackson2/pom.xml b/modules/jooby-jsonrpc-jackson2/pom.xml new file mode 100644 index 0000000000..dce31fb33a --- /dev/null +++ b/modules/jooby-jsonrpc-jackson2/pom.xml @@ -0,0 +1,28 @@ + + + 4.0.0 + + io.jooby + modules + 4.3.0 + + + jooby-jsonrpc-jackson2 + jooby-jsonrpc-jackson2 + + + + io.jooby + jooby-jsonrpc + ${jooby.version} + + + + com.fasterxml.jackson.core + jackson-databind + + + + diff --git a/modules/jooby-jackson/src/main/java/io/jooby/internal/jackson/JacksonJsonRpcDecoder.java b/modules/jooby-jsonrpc-jackson2/src/main/java/io/jooby/internal/jsonrpc/jackson2/JacksonJsonRpcDecoder.java similarity index 92% rename from modules/jooby-jackson/src/main/java/io/jooby/internal/jackson/JacksonJsonRpcDecoder.java rename to modules/jooby-jsonrpc-jackson2/src/main/java/io/jooby/internal/jsonrpc/jackson2/JacksonJsonRpcDecoder.java index e03a33e682..7642f4c6e9 100644 --- a/modules/jooby-jackson/src/main/java/io/jooby/internal/jackson/JacksonJsonRpcDecoder.java +++ b/modules/jooby-jsonrpc-jackson2/src/main/java/io/jooby/internal/jsonrpc/jackson2/JacksonJsonRpcDecoder.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.jsonrpc.jackson2; import java.lang.reflect.Type; @@ -12,7 +12,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.jooby.exception.MissingValueException; import io.jooby.exception.TypeMismatchException; -import io.jooby.rpc.jsonrpc.JsonRpcDecoder; +import io.jooby.jsonrpc.JsonRpcDecoder; public class JacksonJsonRpcDecoder implements JsonRpcDecoder { diff --git a/modules/jooby-jsonrpc-jackson2/src/main/java/io/jooby/internal/jsonrpc/jackson2/JacksonJsonRpcModule.java b/modules/jooby-jsonrpc-jackson2/src/main/java/io/jooby/internal/jsonrpc/jackson2/JacksonJsonRpcModule.java new file mode 100644 index 0000000000..e91130d4ec --- /dev/null +++ b/modules/jooby-jsonrpc-jackson2/src/main/java/io/jooby/internal/jsonrpc/jackson2/JacksonJsonRpcModule.java @@ -0,0 +1,19 @@ +/* + * Jooby https://jooby.io + * Apache License Version 2.0 https://jooby.io/LICENSE.txt + * Copyright 2014 Edgar Espina + */ +package io.jooby.internal.jsonrpc.jackson2; + +import com.fasterxml.jackson.databind.module.SimpleModule; +import io.jooby.jsonrpc.JsonRpcRequest; +import io.jooby.jsonrpc.JsonRpcResponse; + +public class JacksonJsonRpcModule extends SimpleModule { + + public JacksonJsonRpcModule() { + super("json-rpc"); + addDeserializer(JsonRpcRequest.class, new JacksonJsonRpcRequestDeserializer()); + addSerializer(JsonRpcResponse.class, new JacksonJsonRpcResponseSerializer()); + } +} diff --git a/modules/jooby-jackson/src/main/java/io/jooby/internal/jackson/JacksonJsonRpcParser.java b/modules/jooby-jsonrpc-jackson2/src/main/java/io/jooby/internal/jsonrpc/jackson2/JacksonJsonRpcParser.java similarity index 82% rename from modules/jooby-jackson/src/main/java/io/jooby/internal/jackson/JacksonJsonRpcParser.java rename to modules/jooby-jsonrpc-jackson2/src/main/java/io/jooby/internal/jsonrpc/jackson2/JacksonJsonRpcParser.java index 20558663c7..c7941e9660 100644 --- a/modules/jooby-jackson/src/main/java/io/jooby/internal/jackson/JacksonJsonRpcParser.java +++ b/modules/jooby-jsonrpc-jackson2/src/main/java/io/jooby/internal/jsonrpc/jackson2/JacksonJsonRpcParser.java @@ -3,15 +3,15 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.internal.jackson; +package io.jooby.internal.jsonrpc.jackson2; import java.lang.reflect.Type; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import io.jooby.rpc.jsonrpc.JsonRpcDecoder; -import io.jooby.rpc.jsonrpc.JsonRpcParser; -import io.jooby.rpc.jsonrpc.JsonRpcReader; +import io.jooby.jsonrpc.JsonRpcDecoder; +import io.jooby.jsonrpc.JsonRpcParser; +import io.jooby.jsonrpc.JsonRpcReader; public class JacksonJsonRpcParser implements JsonRpcParser { diff --git a/modules/jooby-jackson/src/main/java/io/jooby/internal/jackson/JacksonJsonRpcReader.java b/modules/jooby-jsonrpc-jackson2/src/main/java/io/jooby/internal/jsonrpc/jackson2/JacksonJsonRpcReader.java similarity index 95% rename from modules/jooby-jackson/src/main/java/io/jooby/internal/jackson/JacksonJsonRpcReader.java rename to modules/jooby-jsonrpc-jackson2/src/main/java/io/jooby/internal/jsonrpc/jackson2/JacksonJsonRpcReader.java index 692ac4844e..b98da3698f 100644 --- a/modules/jooby-jackson/src/main/java/io/jooby/internal/jackson/JacksonJsonRpcReader.java +++ b/modules/jooby-jsonrpc-jackson2/src/main/java/io/jooby/internal/jsonrpc/jackson2/JacksonJsonRpcReader.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.jsonrpc.jackson2; import com.fasterxml.jackson.databind.JsonNode; import io.jooby.exception.MissingValueException; import io.jooby.exception.TypeMismatchException; -import io.jooby.rpc.jsonrpc.JsonRpcDecoder; -import io.jooby.rpc.jsonrpc.JsonRpcReader; +import io.jooby.jsonrpc.JsonRpcDecoder; +import io.jooby.jsonrpc.JsonRpcReader; public class JacksonJsonRpcReader implements JsonRpcReader { diff --git a/modules/jooby-jackson/src/main/java/io/jooby/internal/jackson/JacksonJsonRpcRequestDeserializer.java b/modules/jooby-jsonrpc-jackson2/src/main/java/io/jooby/internal/jsonrpc/jackson2/JacksonJsonRpcRequestDeserializer.java similarity index 97% rename from modules/jooby-jackson/src/main/java/io/jooby/internal/jackson/JacksonJsonRpcRequestDeserializer.java rename to modules/jooby-jsonrpc-jackson2/src/main/java/io/jooby/internal/jsonrpc/jackson2/JacksonJsonRpcRequestDeserializer.java index 185a8ca117..4d6e38282f 100644 --- a/modules/jooby-jackson/src/main/java/io/jooby/internal/jackson/JacksonJsonRpcRequestDeserializer.java +++ b/modules/jooby-jsonrpc-jackson2/src/main/java/io/jooby/internal/jsonrpc/jackson2/JacksonJsonRpcRequestDeserializer.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.jsonrpc.jackson2; import java.io.IOException; @@ -12,7 +12,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import com.fasterxml.jackson.databind.node.ArrayNode; -import io.jooby.rpc.jsonrpc.JsonRpcRequest; +import io.jooby.jsonrpc.JsonRpcRequest; public class JacksonJsonRpcRequestDeserializer extends StdDeserializer { diff --git a/modules/jooby-jackson/src/main/java/io/jooby/internal/jackson/JacksonJsonRpcResponseSerializer.java b/modules/jooby-jsonrpc-jackson2/src/main/java/io/jooby/internal/jsonrpc/jackson2/JacksonJsonRpcResponseSerializer.java similarity index 92% rename from modules/jooby-jackson/src/main/java/io/jooby/internal/jackson/JacksonJsonRpcResponseSerializer.java rename to modules/jooby-jsonrpc-jackson2/src/main/java/io/jooby/internal/jsonrpc/jackson2/JacksonJsonRpcResponseSerializer.java index 494e155e16..9f135d8855 100644 --- a/modules/jooby-jackson/src/main/java/io/jooby/internal/jackson/JacksonJsonRpcResponseSerializer.java +++ b/modules/jooby-jsonrpc-jackson2/src/main/java/io/jooby/internal/jsonrpc/jackson2/JacksonJsonRpcResponseSerializer.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.jsonrpc.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.jsonrpc.JsonRpcResponse; +import io.jooby.jsonrpc.JsonRpcResponse; public class JacksonJsonRpcResponseSerializer extends StdSerializer { diff --git a/modules/jooby-jsonrpc-jackson2/src/main/java/io/jooby/jsonrpc/jackson2/JsonRpcJackson2Module.java b/modules/jooby-jsonrpc-jackson2/src/main/java/io/jooby/jsonrpc/jackson2/JsonRpcJackson2Module.java new file mode 100644 index 0000000000..6166dc87d7 --- /dev/null +++ b/modules/jooby-jsonrpc-jackson2/src/main/java/io/jooby/jsonrpc/jackson2/JsonRpcJackson2Module.java @@ -0,0 +1,47 @@ +/* + * Jooby https://jooby.io + * Apache License Version 2.0 https://jooby.io/LICENSE.txt + * Copyright 2014 Edgar Espina + */ +package io.jooby.jsonrpc.jackson2; + +import com.fasterxml.jackson.databind.DatabindException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.exc.MismatchedInputException; +import edu.umd.cs.findbugs.annotations.NonNull; +import io.jooby.Extension; +import io.jooby.Jooby; +import io.jooby.internal.jsonrpc.jackson2.JacksonJsonRpcParser; +import io.jooby.jsonrpc.JsonRpcErrorCode; +import io.jooby.jsonrpc.JsonRpcParser; + +/** + * Implementation of jooby-jsonrpc using Jackson 2.x. It provides the parser, decoder, reader, and + * serializer. + * + *

Usage: + * + *

{@code
+ * {
+ *   install(new JacksonModule());
+ *   install(new JsonRpcJackson2Module());
+ *   install(new JsonRpcModule());
+ * }
+ * }
+ * + * @since 4.3.0 + * @author edgar + */ +public class JsonRpcJackson2Module implements Extension { + @Override + public void install(@NonNull Jooby application) throws Exception { + // JSON-RPC + var services = application.getServices(); + services.put( + JsonRpcParser.class, new JacksonJsonRpcParser(application.require(ObjectMapper.class))); + services + .mapOf(Class.class, JsonRpcErrorCode.class) + .put(MismatchedInputException.class, JsonRpcErrorCode.INVALID_PARAMS) + .put(DatabindException.class, JsonRpcErrorCode.INVALID_PARAMS); + } +} diff --git a/modules/jooby-jsonrpc-jackson2/src/main/java/module-info.java b/modules/jooby-jsonrpc-jackson2/src/main/java/module-info.java new file mode 100644 index 0000000000..7f1bade13c --- /dev/null +++ b/modules/jooby-jsonrpc-jackson2/src/main/java/module-info.java @@ -0,0 +1,29 @@ +/** + * Implementation of jooby-jsonrpc using Jackson 2.x. It provides the parser, decoder, reader, and + * serializer. + * + *

Usage: + * + *

{@code
+ * {
+ *   install(new JacksonModule());
+ *   install(new JsonRpcJackson2Module());
+ *   install(new JsonRpcModule());
+ * }
+ * }
+ * + * @since 4.3.0 + * @author edgar + */ +module io.jooby.jsonrpc.jackson2 { + exports io.jooby.jsonrpc.jackson2; + + provides com.fasterxml.jackson.databind.Module with + io.jooby.internal.jsonrpc.jackson2.JacksonJsonRpcModule; + + requires io.jooby; + requires io.jooby.jsonrpc; + requires static com.github.spotbugs.annotations; + requires typesafe.config; + requires com.fasterxml.jackson.databind; +} diff --git a/modules/jooby-jsonrpc-jackson2/src/main/resources/META-INF/services/com.fasterxml.jackson.databind.Module b/modules/jooby-jsonrpc-jackson2/src/main/resources/META-INF/services/com.fasterxml.jackson.databind.Module new file mode 100644 index 0000000000..0ed0b890b6 --- /dev/null +++ b/modules/jooby-jsonrpc-jackson2/src/main/resources/META-INF/services/com.fasterxml.jackson.databind.Module @@ -0,0 +1 @@ +io.jooby.internal.jsonrpc.jackson2.JacksonJsonRpcModule diff --git a/modules/jooby-jsonrpc-jackson3/pom.xml b/modules/jooby-jsonrpc-jackson3/pom.xml new file mode 100644 index 0000000000..a524f52ddf --- /dev/null +++ b/modules/jooby-jsonrpc-jackson3/pom.xml @@ -0,0 +1,28 @@ + + + 4.0.0 + + io.jooby + modules + 4.3.0 + + + jooby-jsonrpc-jackson3 + jooby-jsonrpc-jackson3 + + + + io.jooby + jooby-jsonrpc + ${jooby.version} + + + + tools.jackson.core + jackson-databind + + + + diff --git a/modules/jooby-jackson3/src/main/java/io/jooby/internal/jackson3/JacksonJsonRpcDecoder.java b/modules/jooby-jsonrpc-jackson3/src/main/java/io/jooby/internal/jsonrpc/jackson3/JacksonJsonRpcDecoder.java similarity index 92% rename from modules/jooby-jackson3/src/main/java/io/jooby/internal/jackson3/JacksonJsonRpcDecoder.java rename to modules/jooby-jsonrpc-jackson3/src/main/java/io/jooby/internal/jsonrpc/jackson3/JacksonJsonRpcDecoder.java index 4f8c0d2166..4426c88e28 100644 --- a/modules/jooby-jackson3/src/main/java/io/jooby/internal/jackson3/JacksonJsonRpcDecoder.java +++ b/modules/jooby-jsonrpc-jackson3/src/main/java/io/jooby/internal/jsonrpc/jackson3/JacksonJsonRpcDecoder.java @@ -3,13 +3,13 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.internal.jackson3; +package io.jooby.internal.jsonrpc.jackson3; import java.lang.reflect.Type; import io.jooby.exception.MissingValueException; import io.jooby.exception.TypeMismatchException; -import io.jooby.rpc.jsonrpc.JsonRpcDecoder; +import io.jooby.jsonrpc.JsonRpcDecoder; import tools.jackson.databind.JavaType; import tools.jackson.databind.JsonNode; import tools.jackson.databind.ObjectMapper; diff --git a/modules/jooby-jsonrpc-jackson3/src/main/java/io/jooby/internal/jsonrpc/jackson3/JacksonJsonRpcModule.java b/modules/jooby-jsonrpc-jackson3/src/main/java/io/jooby/internal/jsonrpc/jackson3/JacksonJsonRpcModule.java new file mode 100644 index 0000000000..e5a889ccc5 --- /dev/null +++ b/modules/jooby-jsonrpc-jackson3/src/main/java/io/jooby/internal/jsonrpc/jackson3/JacksonJsonRpcModule.java @@ -0,0 +1,19 @@ +/* + * Jooby https://jooby.io + * Apache License Version 2.0 https://jooby.io/LICENSE.txt + * Copyright 2014 Edgar Espina + */ +package io.jooby.internal.jsonrpc.jackson3; + +import io.jooby.jsonrpc.JsonRpcRequest; +import io.jooby.jsonrpc.JsonRpcResponse; +import tools.jackson.databind.module.SimpleModule; + +public class JacksonJsonRpcModule extends SimpleModule { + + public JacksonJsonRpcModule() { + super("json-rpc"); + addSerializer(JsonRpcResponse.class, new JacksonJsonRpcResponseSerializer()); + addDeserializer(JsonRpcRequest.class, new JacksonJsonRpcRequestDeserializer()); + } +} diff --git a/modules/jooby-jackson3/src/main/java/io/jooby/internal/jackson3/JacksonJsonRpcParser.java b/modules/jooby-jsonrpc-jackson3/src/main/java/io/jooby/internal/jsonrpc/jackson3/JacksonJsonRpcParser.java similarity index 82% rename from modules/jooby-jackson3/src/main/java/io/jooby/internal/jackson3/JacksonJsonRpcParser.java rename to modules/jooby-jsonrpc-jackson3/src/main/java/io/jooby/internal/jsonrpc/jackson3/JacksonJsonRpcParser.java index 06bb7d233a..6e24908462 100644 --- a/modules/jooby-jackson3/src/main/java/io/jooby/internal/jackson3/JacksonJsonRpcParser.java +++ b/modules/jooby-jsonrpc-jackson3/src/main/java/io/jooby/internal/jsonrpc/jackson3/JacksonJsonRpcParser.java @@ -3,13 +3,13 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.internal.jackson3; +package io.jooby.internal.jsonrpc.jackson3; import java.lang.reflect.Type; -import io.jooby.rpc.jsonrpc.JsonRpcDecoder; -import io.jooby.rpc.jsonrpc.JsonRpcParser; -import io.jooby.rpc.jsonrpc.JsonRpcReader; +import io.jooby.jsonrpc.JsonRpcDecoder; +import io.jooby.jsonrpc.JsonRpcParser; +import io.jooby.jsonrpc.JsonRpcReader; import tools.jackson.databind.JsonNode; import tools.jackson.databind.ObjectMapper; diff --git a/modules/jooby-jackson3/src/main/java/io/jooby/internal/jackson3/JacksonJsonRpcReader.java b/modules/jooby-jsonrpc-jackson3/src/main/java/io/jooby/internal/jsonrpc/jackson3/JacksonJsonRpcReader.java similarity index 95% rename from modules/jooby-jackson3/src/main/java/io/jooby/internal/jackson3/JacksonJsonRpcReader.java rename to modules/jooby-jsonrpc-jackson3/src/main/java/io/jooby/internal/jsonrpc/jackson3/JacksonJsonRpcReader.java index bf1ad7e966..55008247cd 100644 --- a/modules/jooby-jackson3/src/main/java/io/jooby/internal/jackson3/JacksonJsonRpcReader.java +++ b/modules/jooby-jsonrpc-jackson3/src/main/java/io/jooby/internal/jsonrpc/jackson3/JacksonJsonRpcReader.java @@ -3,12 +3,12 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.internal.jackson3; +package io.jooby.internal.jsonrpc.jackson3; import io.jooby.exception.MissingValueException; import io.jooby.exception.TypeMismatchException; -import io.jooby.rpc.jsonrpc.JsonRpcDecoder; -import io.jooby.rpc.jsonrpc.JsonRpcReader; +import io.jooby.jsonrpc.JsonRpcDecoder; +import io.jooby.jsonrpc.JsonRpcReader; import tools.jackson.databind.JsonNode; public class JacksonJsonRpcReader implements JsonRpcReader { diff --git a/modules/jooby-jackson3/src/main/java/io/jooby/internal/jackson3/JacksonJsonRpcRequestDeserializer.java b/modules/jooby-jsonrpc-jackson3/src/main/java/io/jooby/internal/jsonrpc/jackson3/JacksonJsonRpcRequestDeserializer.java similarity index 96% rename from modules/jooby-jackson3/src/main/java/io/jooby/internal/jackson3/JacksonJsonRpcRequestDeserializer.java rename to modules/jooby-jsonrpc-jackson3/src/main/java/io/jooby/internal/jsonrpc/jackson3/JacksonJsonRpcRequestDeserializer.java index a20eb35ad7..8095c1307f 100644 --- a/modules/jooby-jackson3/src/main/java/io/jooby/internal/jackson3/JacksonJsonRpcRequestDeserializer.java +++ b/modules/jooby-jsonrpc-jackson3/src/main/java/io/jooby/internal/jsonrpc/jackson3/JacksonJsonRpcRequestDeserializer.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.jsonrpc.jackson3; -import io.jooby.rpc.jsonrpc.JsonRpcRequest; +import io.jooby.jsonrpc.JsonRpcRequest; import tools.jackson.core.JsonParser; import tools.jackson.databind.DeserializationContext; import tools.jackson.databind.JsonNode; diff --git a/modules/jooby-jackson3/src/main/java/io/jooby/internal/jackson3/JacksonJsonRpcResponseSerializer.java b/modules/jooby-jsonrpc-jackson3/src/main/java/io/jooby/internal/jsonrpc/jackson3/JacksonJsonRpcResponseSerializer.java similarity index 92% rename from modules/jooby-jackson3/src/main/java/io/jooby/internal/jackson3/JacksonJsonRpcResponseSerializer.java rename to modules/jooby-jsonrpc-jackson3/src/main/java/io/jooby/internal/jsonrpc/jackson3/JacksonJsonRpcResponseSerializer.java index 45dc5b3ea4..200dd9585e 100644 --- a/modules/jooby-jackson3/src/main/java/io/jooby/internal/jackson3/JacksonJsonRpcResponseSerializer.java +++ b/modules/jooby-jsonrpc-jackson3/src/main/java/io/jooby/internal/jsonrpc/jackson3/JacksonJsonRpcResponseSerializer.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.jsonrpc.jackson3; -import io.jooby.rpc.jsonrpc.JsonRpcResponse; +import io.jooby.jsonrpc.JsonRpcResponse; import tools.jackson.core.JacksonException; import tools.jackson.core.JsonGenerator; import tools.jackson.databind.SerializationContext; diff --git a/modules/jooby-jsonrpc-jackson3/src/main/java/io/jooby/jsonrpc/jackson3/JsonRpcJackson3Module.java b/modules/jooby-jsonrpc-jackson3/src/main/java/io/jooby/jsonrpc/jackson3/JsonRpcJackson3Module.java new file mode 100644 index 0000000000..4245c0361f --- /dev/null +++ b/modules/jooby-jsonrpc-jackson3/src/main/java/io/jooby/jsonrpc/jackson3/JsonRpcJackson3Module.java @@ -0,0 +1,49 @@ +/* + * Jooby https://jooby.io + * Apache License Version 2.0 https://jooby.io/LICENSE.txt + * Copyright 2014 Edgar Espina + */ +package io.jooby.jsonrpc.jackson3; + +import edu.umd.cs.findbugs.annotations.NonNull; +import io.jooby.Extension; +import io.jooby.Jooby; +import io.jooby.internal.jsonrpc.jackson3.JacksonJsonRpcParser; +import io.jooby.jsonrpc.JsonRpcErrorCode; +import io.jooby.jsonrpc.JsonRpcParser; +import tools.jackson.core.exc.StreamReadException; +import tools.jackson.databind.DatabindException; +import tools.jackson.databind.ObjectMapper; +import tools.jackson.databind.exc.MismatchedInputException; + +/** + * Implementation of jooby-jsonrpc using Jackson 3.x. It provides the parser, decoder, reader, and + * serializer. + * + *

Usage: + * + *

{@code
+ * {
+ *   install(new Jackson3Module());
+ *   install(new JsonRpcJackson3Module());
+ *   install(new JsonRpcModule());
+ * }
+ * }
+ * + * @since 4.3.0 + * @author edgar + */ +public class JsonRpcJackson3Module implements Extension { + @Override + public void install(@NonNull Jooby application) throws Exception { + // JSON-RPC + var services = application.getServices(); + services.put( + JsonRpcParser.class, new JacksonJsonRpcParser(application.require(ObjectMapper.class))); + services + .mapOf(Class.class, JsonRpcErrorCode.class) + .put(StreamReadException.class, JsonRpcErrorCode.INVALID_PARAMS) + .put(MismatchedInputException.class, JsonRpcErrorCode.INVALID_PARAMS) + .put(DatabindException.class, JsonRpcErrorCode.INVALID_PARAMS); + } +} diff --git a/modules/jooby-jsonrpc-jackson3/src/main/java/module-info.java b/modules/jooby-jsonrpc-jackson3/src/main/java/module-info.java new file mode 100644 index 0000000000..177a8b220c --- /dev/null +++ b/modules/jooby-jsonrpc-jackson3/src/main/java/module-info.java @@ -0,0 +1,29 @@ +/** + * Implementation of jooby-jsonrpc using Jackson 3.x. It provides the parser, decoder, reader, and + * serializer. + * + *

Usage: + * + *

{@code
+ * {
+ *   install(new Jackson3Module());
+ *   install(new JsonRpcJackson3Module());
+ *   install(new JsonRpcModule());
+ * }
+ * }
+ * + * @since 4.3.0 + * @author edgar + */ +module io.jooby.jsonrpc.jackson3 { + exports io.jooby.jsonrpc.jackson3; + + provides tools.jackson.databind.JacksonModule with + io.jooby.internal.jsonrpc.jackson3.JacksonJsonRpcModule; + + requires io.jooby; + requires io.jooby.jsonrpc; + requires static com.github.spotbugs.annotations; + requires typesafe.config; + requires tools.jackson.databind; +} diff --git a/modules/jooby-jsonrpc-jackson3/src/main/resources/META-INF/services/tools.jackson.databind.JacksonModule b/modules/jooby-jsonrpc-jackson3/src/main/resources/META-INF/services/tools.jackson.databind.JacksonModule new file mode 100644 index 0000000000..2c5b86e551 --- /dev/null +++ b/modules/jooby-jsonrpc-jackson3/src/main/resources/META-INF/services/tools.jackson.databind.JacksonModule @@ -0,0 +1 @@ +io.jooby.internal.jsonrpc.jackson3.JacksonJsonRpcModule diff --git a/modules/jooby-jsonrpc/pom.xml b/modules/jooby-jsonrpc/pom.xml new file mode 100644 index 0000000000..cc9bf1f728 --- /dev/null +++ b/modules/jooby-jsonrpc/pom.xml @@ -0,0 +1,23 @@ + + + 4.0.0 + + io.jooby + modules + 4.3.0 + + + jooby-jsonrpc + jooby-jsonrpc + + + + io.jooby + jooby + ${jooby.version} + + + + diff --git a/jooby/src/main/java/io/jooby/annotation/JsonRpc.java b/modules/jooby-jsonrpc/src/main/java/io/jooby/annotation/jsonrpc/JsonRpc.java similarity index 98% rename from jooby/src/main/java/io/jooby/annotation/JsonRpc.java rename to modules/jooby-jsonrpc/src/main/java/io/jooby/annotation/jsonrpc/JsonRpc.java index e0f0c0d681..0fd190357e 100644 --- a/jooby/src/main/java/io/jooby/annotation/JsonRpc.java +++ b/modules/jooby-jsonrpc/src/main/java/io/jooby/annotation/jsonrpc/JsonRpc.java @@ -3,7 +3,7 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.annotation; +package io.jooby.annotation.jsonrpc; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/jooby/src/main/java/io/jooby/rpc/jsonrpc/JsonRpcDecoder.java b/modules/jooby-jsonrpc/src/main/java/io/jooby/jsonrpc/JsonRpcDecoder.java similarity index 97% rename from jooby/src/main/java/io/jooby/rpc/jsonrpc/JsonRpcDecoder.java rename to modules/jooby-jsonrpc/src/main/java/io/jooby/jsonrpc/JsonRpcDecoder.java index b7d75f3ab1..232ea3b3b9 100644 --- a/jooby/src/main/java/io/jooby/rpc/jsonrpc/JsonRpcDecoder.java +++ b/modules/jooby-jsonrpc/src/main/java/io/jooby/jsonrpc/JsonRpcDecoder.java @@ -3,7 +3,7 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.rpc.jsonrpc; +package io.jooby.jsonrpc; /** * A pre-resolved decoder used at runtime to deserialize JSON-RPC parameter nodes into complex Java diff --git a/jooby/src/main/java/io/jooby/rpc/jsonrpc/JsonRpcErrorCode.java b/modules/jooby-jsonrpc/src/main/java/io/jooby/jsonrpc/JsonRpcErrorCode.java similarity index 99% rename from jooby/src/main/java/io/jooby/rpc/jsonrpc/JsonRpcErrorCode.java rename to modules/jooby-jsonrpc/src/main/java/io/jooby/jsonrpc/JsonRpcErrorCode.java index 929b4306a2..b0af276159 100644 --- a/jooby/src/main/java/io/jooby/rpc/jsonrpc/JsonRpcErrorCode.java +++ b/modules/jooby-jsonrpc/src/main/java/io/jooby/jsonrpc/JsonRpcErrorCode.java @@ -3,7 +3,7 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.rpc.jsonrpc; +package io.jooby.jsonrpc; import io.jooby.StatusCode; diff --git a/jooby/src/main/java/io/jooby/rpc/jsonrpc/JsonRpcException.java b/modules/jooby-jsonrpc/src/main/java/io/jooby/jsonrpc/JsonRpcException.java similarity index 98% rename from jooby/src/main/java/io/jooby/rpc/jsonrpc/JsonRpcException.java rename to modules/jooby-jsonrpc/src/main/java/io/jooby/jsonrpc/JsonRpcException.java index 9566a124a8..31c8c7279b 100644 --- a/jooby/src/main/java/io/jooby/rpc/jsonrpc/JsonRpcException.java +++ b/modules/jooby-jsonrpc/src/main/java/io/jooby/jsonrpc/JsonRpcException.java @@ -3,7 +3,7 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.rpc.jsonrpc; +package io.jooby.jsonrpc; /** * Exception thrown when a JSON-RPC error occurs during routing, parsing, or execution. diff --git a/jooby/src/main/java/io/jooby/rpc/jsonrpc/JsonRpcModule.java b/modules/jooby-jsonrpc/src/main/java/io/jooby/jsonrpc/JsonRpcModule.java similarity index 93% rename from jooby/src/main/java/io/jooby/rpc/jsonrpc/JsonRpcModule.java rename to modules/jooby-jsonrpc/src/main/java/io/jooby/jsonrpc/JsonRpcModule.java index 632731ee69..6572d771ba 100644 --- a/jooby/src/main/java/io/jooby/rpc/jsonrpc/JsonRpcModule.java +++ b/modules/jooby-jsonrpc/src/main/java/io/jooby/jsonrpc/JsonRpcModule.java @@ -3,7 +3,7 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.rpc.jsonrpc; +package io.jooby.jsonrpc; import java.util.*; @@ -15,7 +15,7 @@ import io.jooby.exception.TypeMismatchException; /** - * Global Tier 1 Dispatcher for JSON-RPC 2.0 requests. * + * Global Tier 1 Dispatcher for JSON-RPC 2.0 requests. * *

This dispatcher acts as the central entry point for all JSON-RPC traffic. It manages the * lifecycle of a request by: @@ -35,8 +35,12 @@ *

Usage: * *

{@code
- * install(new JsonRpcDispatcher());
- * services().put(JsonRpcService.class, new MyServiceRpc(new MyService()));
+ * install(new Jackson3Module());
+ *
+ * install(new JsonRpcJackson3Module());
+ *
+ * install(new JsonRpcModule(new MyServiceRpc_()));
+ *
  * }
* * @author Edgar Espina @@ -47,11 +51,17 @@ public class JsonRpcModule implements Extension { private final Map services = new HashMap<>(); private final String path; - public JsonRpcModule(String path) { + public JsonRpcModule(String path, JsonRpcService service, JsonRpcService... services) { this.path = path; + registry(service); + Arrays.stream(services).forEach(this::registry); + } + + public JsonRpcModule(JsonRpcService service, JsonRpcService... services) { + this("/rpc", service, services); } - public void add(JsonRpcService service) { + private void registry(JsonRpcService service) { for (var method : service.getMethods()) { this.services.put(method, service); } diff --git a/jooby/src/main/java/io/jooby/rpc/jsonrpc/JsonRpcParser.java b/modules/jooby-jsonrpc/src/main/java/io/jooby/jsonrpc/JsonRpcParser.java similarity index 98% rename from jooby/src/main/java/io/jooby/rpc/jsonrpc/JsonRpcParser.java rename to modules/jooby-jsonrpc/src/main/java/io/jooby/jsonrpc/JsonRpcParser.java index c42732ab62..3c557113f7 100644 --- a/jooby/src/main/java/io/jooby/rpc/jsonrpc/JsonRpcParser.java +++ b/modules/jooby-jsonrpc/src/main/java/io/jooby/jsonrpc/JsonRpcParser.java @@ -3,7 +3,7 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.rpc.jsonrpc; +package io.jooby.jsonrpc; import java.lang.reflect.Type; diff --git a/jooby/src/main/java/io/jooby/rpc/jsonrpc/JsonRpcReader.java b/modules/jooby-jsonrpc/src/main/java/io/jooby/jsonrpc/JsonRpcReader.java similarity index 99% rename from jooby/src/main/java/io/jooby/rpc/jsonrpc/JsonRpcReader.java rename to modules/jooby-jsonrpc/src/main/java/io/jooby/jsonrpc/JsonRpcReader.java index 2f6bd6696b..e08d34f5b2 100644 --- a/jooby/src/main/java/io/jooby/rpc/jsonrpc/JsonRpcReader.java +++ b/modules/jooby-jsonrpc/src/main/java/io/jooby/jsonrpc/JsonRpcReader.java @@ -3,7 +3,7 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.rpc.jsonrpc; +package io.jooby.jsonrpc; import io.jooby.exception.MissingValueException; diff --git a/jooby/src/main/java/io/jooby/rpc/jsonrpc/JsonRpcRequest.java b/modules/jooby-jsonrpc/src/main/java/io/jooby/jsonrpc/JsonRpcRequest.java similarity index 99% rename from jooby/src/main/java/io/jooby/rpc/jsonrpc/JsonRpcRequest.java rename to modules/jooby-jsonrpc/src/main/java/io/jooby/jsonrpc/JsonRpcRequest.java index 761a593851..82c6e89f9b 100644 --- a/jooby/src/main/java/io/jooby/rpc/jsonrpc/JsonRpcRequest.java +++ b/modules/jooby-jsonrpc/src/main/java/io/jooby/jsonrpc/JsonRpcRequest.java @@ -3,7 +3,7 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.rpc.jsonrpc; +package io.jooby.jsonrpc; import java.util.ArrayList; import java.util.Collections; diff --git a/jooby/src/main/java/io/jooby/rpc/jsonrpc/JsonRpcResponse.java b/modules/jooby-jsonrpc/src/main/java/io/jooby/jsonrpc/JsonRpcResponse.java similarity index 94% rename from jooby/src/main/java/io/jooby/rpc/jsonrpc/JsonRpcResponse.java rename to modules/jooby-jsonrpc/src/main/java/io/jooby/jsonrpc/JsonRpcResponse.java index 408703716b..da0f0f5037 100644 --- a/jooby/src/main/java/io/jooby/rpc/jsonrpc/JsonRpcResponse.java +++ b/modules/jooby-jsonrpc/src/main/java/io/jooby/jsonrpc/JsonRpcResponse.java @@ -3,7 +3,9 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.rpc.jsonrpc; +package io.jooby.jsonrpc; + +import edu.umd.cs.findbugs.annotations.Nullable; /** * Represents a JSON-RPC 2.0 Response object. @@ -73,7 +75,7 @@ public void setResult(Object result) { this.result = result; } - public ErrorDetail getError() { + public @Nullable ErrorDetail getError() { return error; } @@ -81,7 +83,7 @@ public void setError(ErrorDetail error) { this.error = error; } - public Object getId() { + public @Nullable Object getId() { return id; } diff --git a/jooby/src/main/java/io/jooby/rpc/jsonrpc/JsonRpcService.java b/modules/jooby-jsonrpc/src/main/java/io/jooby/jsonrpc/JsonRpcService.java similarity index 74% rename from jooby/src/main/java/io/jooby/rpc/jsonrpc/JsonRpcService.java rename to modules/jooby-jsonrpc/src/main/java/io/jooby/jsonrpc/JsonRpcService.java index 5bb6d154cf..1dba6aca3c 100644 --- a/jooby/src/main/java/io/jooby/rpc/jsonrpc/JsonRpcService.java +++ b/modules/jooby-jsonrpc/src/main/java/io/jooby/jsonrpc/JsonRpcService.java @@ -3,12 +3,13 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.rpc.jsonrpc; +package io.jooby.jsonrpc; import java.util.List; import edu.umd.cs.findbugs.annotations.NonNull; import io.jooby.Context; +import io.jooby.Jooby; /** * Interface for generated JSON-RPC service glue code (*Rpc classes). @@ -25,6 +26,15 @@ public interface JsonRpcService { */ List getMethods(); + /** + * Registers the JSON-RPC service with the provided Jooby application. + * + * @param application The Jooby application instance where the JSON-RPC service will be installed. + * Must not be null. + * @throws Exception If registration fails. + */ + void install(@NonNull Jooby application) throws Exception; + /** * Executes the requested method using the provided context and request data. * diff --git a/modules/jooby-jsonrpc/src/main/java/io/jooby/jsonrpc/package-info.java b/modules/jooby-jsonrpc/src/main/java/io/jooby/jsonrpc/package-info.java new file mode 100644 index 0000000000..5a3c01923f --- /dev/null +++ b/modules/jooby-jsonrpc/src/main/java/io/jooby/jsonrpc/package-info.java @@ -0,0 +1,34 @@ +/** + * Global Tier 1 Dispatcher for JSON-RPC 2.0 requests. + * + *

This dispatcher acts as the central entry point for all JSON-RPC traffic. It manages the + * lifecycle of a request by: + * + *

    + *
  • Parsing the incoming body into a {@link io.jooby.jsonrpc.JsonRpcRequest} (supporting both + * single and batch shapes). + *
  • Iterating through registered {@link io.jooby.jsonrpc.JsonRpcService} instances to find a + * matching namespace. + *
  • Handling Notifications (requests without an {@code id}) by suppressing + * responses. + *
  • Unifying batch results into a single JSON array or a single object response as per the + * spec. + *
+ * + *

* + * + *

Usage: + * + *

{@code
+ * install(new Jackson3Module());
+ *
+ * install(new JsonRpcJackson3Module());
+ *
+ * install(new JsonRpcModule(new MyServiceRpc_()));
+ * }
+ * + * @author Edgar Espina + * @since 4.0.17 + */ +@edu.umd.cs.findbugs.annotations.ReturnValuesAreNonnullByDefault +package io.jooby.jsonrpc; diff --git a/modules/jooby-jsonrpc/src/main/java/module-info.java b/modules/jooby-jsonrpc/src/main/java/module-info.java new file mode 100644 index 0000000000..b38a605ecc --- /dev/null +++ b/modules/jooby-jsonrpc/src/main/java/module-info.java @@ -0,0 +1,41 @@ +/** + * Global Tier 1 Dispatcher for JSON-RPC 2.0 requests. + * + *

This dispatcher acts as the central entry point for all JSON-RPC traffic. It manages the + * lifecycle of a request by: + * + *

    + *
  • Parsing the incoming body into a {@link io.jooby.jsonrpc.JsonRpcRequest} (supporting both + * single and batch shapes). + *
  • Iterating through registered {@link io.jooby.jsonrpc.JsonRpcService} instances to find a + * matching namespace. + *
  • Handling Notifications (requests without an {@code id}) by suppressing + * responses. + *
  • Unifying batch results into a single JSON array or a single object response as per the + * spec. + *
+ * + *

* + * + *

Usage: + * + *

{@code
+ * install(new Jackson3Module());
+ *
+ * install(new JsonRpcJackson3Module());
+ *
+ * install(new JsonRpcModule(new MyServiceRpc_()));
+ * }
+ * + * @author Edgar Espina + * @since 4.0.17 + */ +module io.jooby.jsonrpc { + exports io.jooby.jsonrpc; + exports io.jooby.annotation.jsonrpc; + + requires io.jooby; + requires static com.github.spotbugs.annotations; + requires typesafe.config; + requires org.slf4j; +} diff --git a/modules/jooby-jstachio/pom.xml b/modules/jooby-jstachio/pom.xml index 1320cc3f43..1e5b8ed430 100644 --- a/modules/jooby-jstachio/pom.xml +++ b/modules/jooby-jstachio/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-jstachio jooby-jstachio diff --git a/modules/jooby-jte/pom.xml b/modules/jooby-jte/pom.xml index 96c2c66157..b7d1a9f1f1 100644 --- a/modules/jooby-jte/pom.xml +++ b/modules/jooby-jte/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-jte jooby-jte diff --git a/modules/jooby-jwt/pom.xml b/modules/jooby-jwt/pom.xml index 63319150cd..b7fcccaf11 100644 --- a/modules/jooby-jwt/pom.xml +++ b/modules/jooby-jwt/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-jwt jooby-jwt diff --git a/modules/jooby-kafka/pom.xml b/modules/jooby-kafka/pom.xml index 9db9552a42..e17451a1cb 100644 --- a/modules/jooby-kafka/pom.xml +++ b/modules/jooby-kafka/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-kafka jooby-kafka diff --git a/modules/jooby-kotlin/pom.xml b/modules/jooby-kotlin/pom.xml index 7bacdee692..5ca39d9ac5 100644 --- a/modules/jooby-kotlin/pom.xml +++ b/modules/jooby-kotlin/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-kotlin jooby-kotlin diff --git a/modules/jooby-langchain4j/pom.xml b/modules/jooby-langchain4j/pom.xml index 817c167bb0..bdc2b25791 100644 --- a/modules/jooby-langchain4j/pom.xml +++ b/modules/jooby-langchain4j/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-langchain4j jooby-langchain4j diff --git a/modules/jooby-log4j/pom.xml b/modules/jooby-log4j/pom.xml index b65af70076..761c804174 100644 --- a/modules/jooby-log4j/pom.xml +++ b/modules/jooby-log4j/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-log4j jooby-log4j diff --git a/modules/jooby-logback/pom.xml b/modules/jooby-logback/pom.xml index c0131f058e..294aada900 100644 --- a/modules/jooby-logback/pom.xml +++ b/modules/jooby-logback/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-logback jooby-logback diff --git a/modules/jooby-maven-plugin/pom.xml b/modules/jooby-maven-plugin/pom.xml index 188084c377..42f5f394fa 100644 --- a/modules/jooby-maven-plugin/pom.xml +++ b/modules/jooby-maven-plugin/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-maven-plugin jooby-maven-plugin @@ -31,7 +31,7 @@ io.jooby - jooby-trpc + jooby-trpc-generator ${jooby.version} diff --git a/modules/jooby-mcp-jackson2/pom.xml b/modules/jooby-mcp-jackson2/pom.xml index 3df62cce83..a57ab70a00 100644 --- a/modules/jooby-mcp-jackson2/pom.xml +++ b/modules/jooby-mcp-jackson2/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-mcp-jackson2 @@ -25,7 +25,7 @@ com.github.victools jsonschema-generator - 4.38.0 + 5.0.0 diff --git a/modules/jooby-mcp-jackson3/pom.xml b/modules/jooby-mcp-jackson3/pom.xml index d3ca768983..5b38368211 100644 --- a/modules/jooby-mcp-jackson3/pom.xml +++ b/modules/jooby-mcp-jackson3/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-mcp-jackson3 diff --git a/modules/jooby-mcp/pom.xml b/modules/jooby-mcp/pom.xml index 3595b426cb..fb64abc89f 100644 --- a/modules/jooby-mcp/pom.xml +++ b/modules/jooby-mcp/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-mcp diff --git a/modules/jooby-metrics/pom.xml b/modules/jooby-metrics/pom.xml index 39a97dc5e9..acf9f62932 100644 --- a/modules/jooby-metrics/pom.xml +++ b/modules/jooby-metrics/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-metrics jooby-metrics diff --git a/modules/jooby-mutiny/pom.xml b/modules/jooby-mutiny/pom.xml index 88bbc08db4..a4fdc72090 100644 --- a/modules/jooby-mutiny/pom.xml +++ b/modules/jooby-mutiny/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-mutiny jooby-mutiny diff --git a/modules/jooby-netty/pom.xml b/modules/jooby-netty/pom.xml index d9f07ea0f1..727b659e10 100644 --- a/modules/jooby-netty/pom.xml +++ b/modules/jooby-netty/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-netty jooby-netty diff --git a/modules/jooby-openapi/pom.xml b/modules/jooby-openapi/pom.xml index f6a7089a32..e96a59758b 100644 --- a/modules/jooby-openapi/pom.xml +++ b/modules/jooby-openapi/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-openapi jooby-openapi @@ -156,7 +156,7 @@ net.bytebuddy byte-buddy - 1.18.7 + 1.18.8 test diff --git a/modules/jooby-pac4j/pom.xml b/modules/jooby-pac4j/pom.xml index 3ba6a22370..6c2ce0a1c5 100644 --- a/modules/jooby-pac4j/pom.xml +++ b/modules/jooby-pac4j/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-pac4j jooby-pac4j diff --git a/modules/jooby-pebble/pom.xml b/modules/jooby-pebble/pom.xml index 223a61ff67..4110eeca4a 100644 --- a/modules/jooby-pebble/pom.xml +++ b/modules/jooby-pebble/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-pebble jooby-pebble diff --git a/modules/jooby-quartz/pom.xml b/modules/jooby-quartz/pom.xml index 8d7e331905..b8d4002f57 100644 --- a/modules/jooby-quartz/pom.xml +++ b/modules/jooby-quartz/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-quartz jooby-quartz diff --git a/modules/jooby-reactor/pom.xml b/modules/jooby-reactor/pom.xml index 2eab1c68d9..5062931c00 100644 --- a/modules/jooby-reactor/pom.xml +++ b/modules/jooby-reactor/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-reactor jooby-reactor diff --git a/modules/jooby-redis/pom.xml b/modules/jooby-redis/pom.xml index 5ff8431bf7..4be8db1bb7 100644 --- a/modules/jooby-redis/pom.xml +++ b/modules/jooby-redis/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-redis jooby-redis diff --git a/modules/jooby-redoc/pom.xml b/modules/jooby-redoc/pom.xml index 8856cf0a76..6a618a4f7d 100644 --- a/modules/jooby-redoc/pom.xml +++ b/modules/jooby-redoc/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-redoc jooby-redoc diff --git a/modules/jooby-rocker/pom.xml b/modules/jooby-rocker/pom.xml index 4a9af3083c..8807f4c631 100644 --- a/modules/jooby-rocker/pom.xml +++ b/modules/jooby-rocker/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-rocker jooby-rocker diff --git a/modules/jooby-run/pom.xml b/modules/jooby-run/pom.xml index 5ce9673294..af70d299f3 100644 --- a/modules/jooby-run/pom.xml +++ b/modules/jooby-run/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-run jooby-run diff --git a/modules/jooby-rxjava3/pom.xml b/modules/jooby-rxjava3/pom.xml index 791d362709..925aacbb3e 100644 --- a/modules/jooby-rxjava3/pom.xml +++ b/modules/jooby-rxjava3/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-rxjava3 jooby-rxjava3 diff --git a/modules/jooby-stork/pom.xml b/modules/jooby-stork/pom.xml index b267434616..b51a798935 100644 --- a/modules/jooby-stork/pom.xml +++ b/modules/jooby-stork/pom.xml @@ -4,7 +4,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-stork diff --git a/modules/jooby-swagger-ui/pom.xml b/modules/jooby-swagger-ui/pom.xml index f21f0d0ca9..91e14d1f8a 100644 --- a/modules/jooby-swagger-ui/pom.xml +++ b/modules/jooby-swagger-ui/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-swagger-ui jooby-swagger-ui diff --git a/modules/jooby-test/pom.xml b/modules/jooby-test/pom.xml index 1dd5bfcea0..4bce67527f 100644 --- a/modules/jooby-test/pom.xml +++ b/modules/jooby-test/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-test jooby-test diff --git a/modules/jooby-thymeleaf/pom.xml b/modules/jooby-thymeleaf/pom.xml index d86cb9e820..a6b0b57748 100644 --- a/modules/jooby-thymeleaf/pom.xml +++ b/modules/jooby-thymeleaf/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-thymeleaf jooby-thymeleaf diff --git a/modules/jooby-trpc-avaje-jsonb/pom.xml b/modules/jooby-trpc-avaje-jsonb/pom.xml new file mode 100644 index 0000000000..30c6ec39c8 --- /dev/null +++ b/modules/jooby-trpc-avaje-jsonb/pom.xml @@ -0,0 +1,29 @@ + + + 4.0.0 + + io.jooby + modules + 4.3.0 + + + 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..9020242bbe --- /dev/null +++ b/modules/jooby-trpc-avaje-jsonb/src/main/java/io/jooby/trpc/avaje/jsonb/TrpcAvajeJsonbModule.java @@ -0,0 +1,46 @@ +/* + * 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; + +/** + * Implementation of jooby-trpc using avaje-jsonb. It provides the parser, decoder, reader, and + * serializer. + * + *

Usage: + * + *

{@code
+ * {
+ *   install(new AvajeJsonbModule());
+ *   install(new TrpcAvajeJsonbModule());
+ *   install(new TrpcModule());
+ * }
+ * }
+ * + * @since 4.3.0 + * @author edgar + */ +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..b26201af22 --- /dev/null +++ b/modules/jooby-trpc-avaje-jsonb/src/main/java/io/jooby/trpc/avaje/jsonb/TrpcJsonbExtension.java @@ -0,0 +1,24 @@ +/* + * 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; + +/** + * Custom adapter for {@link TrpcResponse}. + * + * @since 4.3.0 + * @author edgar + */ +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/java/io/jooby/trpc/avaje/jsonb/package-info.java b/modules/jooby-trpc-avaje-jsonb/src/main/java/io/jooby/trpc/avaje/jsonb/package-info.java new file mode 100644 index 0000000000..1ef22c3835 --- /dev/null +++ b/modules/jooby-trpc-avaje-jsonb/src/main/java/io/jooby/trpc/avaje/jsonb/package-info.java @@ -0,0 +1,19 @@ +/** + * Implementation of jooby-trpc using avaje-jsonb. It provides the parser, decoder, reader, and + * serializer. + * + *

Usage: + * + *

{@code
+ * {
+ *   install(new AvajeJsonbModule());
+ *   install(new TrpcAvajeJsonbModule());
+ *   install(new TrpcModule());
+ * }
+ * }
+ * + * @since 4.3.0 + * @author edgar + */ +@edu.umd.cs.findbugs.annotations.ReturnValuesAreNonnullByDefault +package io.jooby.trpc.avaje.jsonb; diff --git a/modules/jooby-trpc-avaje-jsonb/src/main/java/module-info.java b/modules/jooby-trpc-avaje-jsonb/src/main/java/module-info.java new file mode 100644 index 0000000000..fe1129d043 --- /dev/null +++ b/modules/jooby-trpc-avaje-jsonb/src/main/java/module-info.java @@ -0,0 +1,29 @@ +/** + * Implementation of jooby-trpc using avaje-jsonb. It provides the parser, decoder, reader, and + * serializer. + * + *

Usage: + * + *

{@code
+ * {
+ *   install(new AvajeJsonbModule());
+ *   install(new TrpcAvajeJsonbModule());
+ *   install(new TrpcModule());
+ * }
+ * }
+ * + * @since 4.3.0 + * @author edgar + */ +module io.jooby.trpc.avaje.jsonb { + exports io.jooby.trpc.avaje.jsonb; + + requires io.jooby; + requires io.jooby.trpc; + requires static com.github.spotbugs.annotations; + requires typesafe.config; + requires io.avaje.jsonb; + + provides io.avaje.jsonb.spi.JsonbComponent with + io.jooby.trpc.avaje.jsonb.TrpcJsonbExtension; +} 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..57dd67196c --- /dev/null +++ b/modules/jooby-trpc-generator/pom.xml @@ -0,0 +1,144 @@ + + + + 4.0.0 + + + io.jooby + modules + 4.3.0 + + 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..16ef9ce522 --- /dev/null +++ b/modules/jooby-trpc-jackson2/pom.xml @@ -0,0 +1,28 @@ + + + 4.0.0 + + io.jooby + modules + 4.3.0 + + + 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..8bffdf17f9 --- /dev/null +++ b/modules/jooby-trpc-jackson2/src/main/java/io/jooby/trpc/jackson2/TrpcJackson2Module.java @@ -0,0 +1,45 @@ +/* + * 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; + +/** + * Implementation of jooby-trpc using Jackson 2.x. It provides the parser, decoder, reader, and + * serializer. + * + *

Usage: + * + *

{@code
+ * {
+ *   install(new JacksonModule());
+ *   install(new TrpcJackson2Module());
+ *   install(new TrpcModule());
+ * }
+ * }
+ * + * @since 4.3.0 + * @author edgar + */ +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/io/jooby/trpc/jackson2/package-info.java b/modules/jooby-trpc-jackson2/src/main/java/io/jooby/trpc/jackson2/package-info.java new file mode 100644 index 0000000000..d715f4a72b --- /dev/null +++ b/modules/jooby-trpc-jackson2/src/main/java/io/jooby/trpc/jackson2/package-info.java @@ -0,0 +1,19 @@ +/** + * Implementation of jooby-trpc using Jackson 2.x. It provides the parser, decoder, reader, and + * serializer. + * + *

Usage: + * + *

{@code
+ * {
+ *   install(new JacksonModule());
+ *   install(new TrpcJackson2Module());
+ *   install(new TrpcModule());
+ * }
+ * }
+ * + * @since 4.3.0 + * @author edgar + */ +@edu.umd.cs.findbugs.annotations.ReturnValuesAreNonnullByDefault +package io.jooby.trpc.jackson2; 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..82ee1e3aac --- /dev/null +++ b/modules/jooby-trpc-jackson2/src/main/java/module-info.java @@ -0,0 +1,26 @@ +/** + * Implementation of jooby-trpc using Jackson 2.x. It provides the parser, decoder, reader, and + * serializer. + * + *

Usage: + * + *

{@code
+ * {
+ *   install(new JacksonModule());
+ *   install(new TrpcJackson2Module());
+ *   install(new TrpcModule());
+ * }
+ * }
+ * + * @since 4.3.0 + * @author edgar + */ +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..2ae4b016b2 --- /dev/null +++ b/modules/jooby-trpc-jackson3/pom.xml @@ -0,0 +1,29 @@ + + + 4.0.0 + + io.jooby + modules + 4.3.0 + + + 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..e8b0031815 --- /dev/null +++ b/modules/jooby-trpc-jackson3/src/main/java/io/jooby/trpc/jackson3/TrpcJackson3Module.java @@ -0,0 +1,58 @@ +/* + * 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; + +/** + * Implementation of jooby-trpc using Jackson 3.x. It provides the parser, decoder, reader, and + * serializer. + * + *

Usage: + * + *

{@code
+ * {
+ *   install(new Jackson3Module());
+ *   install(new TrpcJackson3Module());
+ *   install(new TrpcModule());
+ * }
+ * }
+ * + * @since 4.3.0 + * @author edgar + */ +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/io/jooby/trpc/jackson3/package-info.java b/modules/jooby-trpc-jackson3/src/main/java/io/jooby/trpc/jackson3/package-info.java new file mode 100644 index 0000000000..f7d311e92d --- /dev/null +++ b/modules/jooby-trpc-jackson3/src/main/java/io/jooby/trpc/jackson3/package-info.java @@ -0,0 +1,19 @@ +/** + * Implementation of jooby-trpc using Jackson 3.x. It provides the parser, decoder, reader, and + * serializer. + * + *

Usage: + * + *

{@code
+ * {
+ *   install(new Jackson3Module());
+ *   install(new TrpcJackson3Module());
+ *   install(new TrpcModule());
+ * }
+ * }
+ * + * @since 4.3.0 + * @author edgar + */ +@edu.umd.cs.findbugs.annotations.ReturnValuesAreNonnullByDefault +package io.jooby.trpc.jackson3; 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..d4346c0c76 --- /dev/null +++ b/modules/jooby-trpc-jackson3/src/main/java/module-info.java @@ -0,0 +1,27 @@ +/** + * Implementation of jooby-trpc using Jackson 3.x. It provides the parser, decoder, reader, and + * serializer. + * + *

Usage: + * + *

{@code
+ * {
+ *   install(new Jackson3Module());
+ *   install(new TrpcJackson3Module());
+ *   install(new TrpcModule());
+ * }
+ * }
+ * + * @since 4.3.0 + * @author edgar + */ +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 f98b3b7222..2981877869 100644 --- a/modules/jooby-trpc/pom.xml +++ b/modules/jooby-trpc/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-trpc jooby-trpc @@ -18,24 +18,6 @@ ${jooby.version}
- - - jakarta.ws.rs - 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: * *

    - *
  • Explicit tRPC Annotations: Use {@link Trpc.Query} for read-only operations (mapped - * to HTTP GET) and {@link Trpc.Mutation} for state-changing operations (mapped to HTTP POST). + *
  • Explicit tRPC Annotations: Use {@link Query} for read-only operations (mapped to + * HTTP GET) and {@link Mutation} for state-changing operations (mapped to HTTP POST). *
  • Hybrid HTTP Annotations: Combine the base {@code @Trpc} annotation with standard * HTTP annotations. A {@code @GET} annotation maps to a query, while {@code @POST}, * {@code @PUT}, {@code @PATCH}, and {@code @DELETE} map to a mutation. diff --git a/jooby/src/main/java/io/jooby/rpc/trpc/TrpcDecoder.java b/modules/jooby-trpc/src/main/java/io/jooby/trpc/TrpcDecoder.java similarity index 98% rename from jooby/src/main/java/io/jooby/rpc/trpc/TrpcDecoder.java rename to modules/jooby-trpc/src/main/java/io/jooby/trpc/TrpcDecoder.java index 2c52b0b229..43f7491813 100644 --- a/jooby/src/main/java/io/jooby/rpc/trpc/TrpcDecoder.java +++ b/modules/jooby-trpc/src/main/java/io/jooby/trpc/TrpcDecoder.java @@ -3,7 +3,7 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.rpc.trpc; +package io.jooby.trpc; /** * A pre-resolved decoder used at runtime to deserialize tRPC network payloads into complex Java diff --git a/jooby/src/main/java/io/jooby/rpc/trpc/TrpcErrorCode.java b/modules/jooby-trpc/src/main/java/io/jooby/trpc/TrpcErrorCode.java similarity index 99% rename from jooby/src/main/java/io/jooby/rpc/trpc/TrpcErrorCode.java rename to modules/jooby-trpc/src/main/java/io/jooby/trpc/TrpcErrorCode.java index f242f50d58..7226483c34 100644 --- a/jooby/src/main/java/io/jooby/rpc/trpc/TrpcErrorCode.java +++ b/modules/jooby-trpc/src/main/java/io/jooby/trpc/TrpcErrorCode.java @@ -3,7 +3,7 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.rpc.trpc; +package io.jooby.trpc; import io.jooby.StatusCode; diff --git a/jooby/src/main/java/io/jooby/rpc/trpc/TrpcErrorHandler.java b/modules/jooby-trpc/src/main/java/io/jooby/trpc/TrpcErrorHandler.java similarity index 99% rename from jooby/src/main/java/io/jooby/rpc/trpc/TrpcErrorHandler.java rename to modules/jooby-trpc/src/main/java/io/jooby/trpc/TrpcErrorHandler.java index c3ca751d3c..aef5d3124b 100644 --- a/jooby/src/main/java/io/jooby/rpc/trpc/TrpcErrorHandler.java +++ b/modules/jooby-trpc/src/main/java/io/jooby/trpc/TrpcErrorHandler.java @@ -3,7 +3,7 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.rpc.trpc; +package io.jooby.trpc; import java.util.Map; import java.util.Optional; diff --git a/jooby/src/main/java/io/jooby/rpc/trpc/TrpcException.java b/modules/jooby-trpc/src/main/java/io/jooby/trpc/TrpcException.java similarity index 99% rename from jooby/src/main/java/io/jooby/rpc/trpc/TrpcException.java rename to modules/jooby-trpc/src/main/java/io/jooby/trpc/TrpcException.java index e4d79030fd..592805bb64 100644 --- a/jooby/src/main/java/io/jooby/rpc/trpc/TrpcException.java +++ b/modules/jooby-trpc/src/main/java/io/jooby/trpc/TrpcException.java @@ -3,7 +3,7 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.rpc.trpc; +package io.jooby.trpc; import java.util.LinkedHashMap; import java.util.Map; diff --git a/jooby/src/main/java/io/jooby/rpc/trpc/TrpcModule.java b/modules/jooby-trpc/src/main/java/io/jooby/trpc/TrpcModule.java similarity index 55% rename from jooby/src/main/java/io/jooby/rpc/trpc/TrpcModule.java rename to modules/jooby-trpc/src/main/java/io/jooby/trpc/TrpcModule.java index ed80262cad..ce38a5b5a2 100644 --- a/jooby/src/main/java/io/jooby/rpc/trpc/TrpcModule.java +++ b/modules/jooby-trpc/src/main/java/io/jooby/trpc/TrpcModule.java @@ -3,7 +3,10 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.rpc.trpc; +package io.jooby.trpc; + +import java.util.List; +import java.util.stream.Stream; import edu.umd.cs.findbugs.annotations.NonNull; import io.jooby.Extension; @@ -28,18 +31,45 @@ *
    {@code
      * {
      * // 1. Install a JSON engine (Prerequisite)
    - * install(new JacksonModule());
    + * install(new Jackson3Module())
      *
    - * // 2. Install the tRPC extension
    - * install(new TrpcModule());
    + * // 2. JSON implementation of protocol
    + * install(new TrpcJackson3Module());
      *
    - * // 3. Register your @Trpc annotated controllers
    - * mvc(new MovieService_());
    + * // 3. Install the tRPC extension
    + * install(new TrpcModule(MovieServiceTrpc_()));
      * }
      * }
    */ public class TrpcModule implements Extension { + private final String path; + private final List services; + + /** + * Creates a new instance of {@code TrpcModule} with the specified base path and tRPC services. + * + * @param path The base path for all tRPC routes. This is the root URL prefix where all tRPC + * services will be registered. Must not be {@code null}. + * @param service The primary tRPC service to register. Must not be {@code null}. + * @param services Additional tRPC services to register (if any). Optional and may be omitted. + */ + public TrpcModule(String path, TrpcService service, TrpcService... services) { + this.path = path; + this.services = Stream.concat(Stream.of(service), Stream.of(services)).toList(); + } + + /** + * Constructs a new {@code TrpcModule} with the default base path: trpc and the + * provided services. + * + * @param service The primary tRPC service to register. Must not be {@code null}. + * @param services Additional tRPC services to register (if any). Optional and may be omitted. + */ + public TrpcModule(TrpcService service, TrpcService... services) { + this("/trpc", service, services); + } + /** * Installs the tRPC extension into the Jooby application. * @@ -59,15 +89,19 @@ public class TrpcModule implements Extension { */ @Override public void install(@NonNull Jooby app) throws Exception { - var services = app.getServices(); + var registry = app.getServices(); // Ensure a JSON module has provided the necessary parser - services.require(TrpcParser.class); + registry.require(TrpcParser.class); // Initialize the custom exception mapping registry - services.mapOf(Class.class, TrpcErrorCode.class); + registry.mapOf(Class.class, TrpcErrorCode.class); // Register the specialized JSON-RPC error formatter app.error(new TrpcErrorHandler()); + + for (var service : services) { + service.install(path, app); + } } } diff --git a/jooby/src/main/java/io/jooby/rpc/trpc/TrpcParser.java b/modules/jooby-trpc/src/main/java/io/jooby/trpc/TrpcParser.java similarity index 99% rename from jooby/src/main/java/io/jooby/rpc/trpc/TrpcParser.java rename to modules/jooby-trpc/src/main/java/io/jooby/trpc/TrpcParser.java index 851c544b08..757c9c21f3 100644 --- a/jooby/src/main/java/io/jooby/rpc/trpc/TrpcParser.java +++ b/modules/jooby-trpc/src/main/java/io/jooby/trpc/TrpcParser.java @@ -3,7 +3,7 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.rpc.trpc; +package io.jooby.trpc; import java.lang.reflect.Type; diff --git a/jooby/src/main/java/io/jooby/rpc/trpc/TrpcReader.java b/modules/jooby-trpc/src/main/java/io/jooby/trpc/TrpcReader.java similarity index 99% rename from jooby/src/main/java/io/jooby/rpc/trpc/TrpcReader.java rename to modules/jooby-trpc/src/main/java/io/jooby/trpc/TrpcReader.java index 3963b55f3f..a2a1646a00 100644 --- a/jooby/src/main/java/io/jooby/rpc/trpc/TrpcReader.java +++ b/modules/jooby-trpc/src/main/java/io/jooby/trpc/TrpcReader.java @@ -3,7 +3,7 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.rpc.trpc; +package io.jooby.trpc; import io.jooby.exception.MissingValueException; diff --git a/jooby/src/main/java/io/jooby/rpc/trpc/TrpcResponse.java b/modules/jooby-trpc/src/main/java/io/jooby/trpc/TrpcResponse.java similarity index 98% rename from jooby/src/main/java/io/jooby/rpc/trpc/TrpcResponse.java rename to modules/jooby-trpc/src/main/java/io/jooby/trpc/TrpcResponse.java index dc3fbeccb9..5bfcc9938f 100644 --- a/jooby/src/main/java/io/jooby/rpc/trpc/TrpcResponse.java +++ b/modules/jooby-trpc/src/main/java/io/jooby/trpc/TrpcResponse.java @@ -3,7 +3,7 @@ * Apache License Version 2.0 https://jooby.io/LICENSE.txt * Copyright 2014 Edgar Espina */ -package io.jooby.rpc.trpc; +package io.jooby.trpc; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; diff --git a/modules/jooby-trpc/src/main/java/io/jooby/trpc/TrpcService.java b/modules/jooby-trpc/src/main/java/io/jooby/trpc/TrpcService.java new file mode 100644 index 0000000000..a080d35af6 --- /dev/null +++ b/modules/jooby-trpc/src/main/java/io/jooby/trpc/TrpcService.java @@ -0,0 +1,27 @@ +/* + * Jooby https://jooby.io + * Apache License Version 2.0 https://jooby.io/LICENSE.txt + * Copyright 2014 Edgar Espina + */ +package io.jooby.trpc; + +import edu.umd.cs.findbugs.annotations.NonNull; +import io.jooby.Jooby; + +/** + * Generated tRPC service. Generated service ends with Trpc_ suffix. + * + * @author edgar + * @since 4.3.0 + */ +public interface TrpcService { + + /** + * Install generate tRPC routes. + * + * @param path Base path. Defaults to /trpc. + * @param application Main application. + * @throws Exception If something goes wrong. + */ + void install(@NonNull String path, @NonNull Jooby application) throws Exception; +} diff --git a/modules/jooby-trpc/src/main/java/module-info.java b/modules/jooby-trpc/src/main/java/module-info.java new file mode 100644 index 0000000000..6a7be84fa6 --- /dev/null +++ b/modules/jooby-trpc/src/main/java/module-info.java @@ -0,0 +1,8 @@ +module io.jooby.trpc { + exports io.jooby.trpc; + exports io.jooby.annotation.trpc; + + requires io.jooby; + requires static com.github.spotbugs.annotations; + requires typesafe.config; +} diff --git a/modules/jooby-undertow/pom.xml b/modules/jooby-undertow/pom.xml index 9d2d1b7bf5..c53ba9e090 100644 --- a/modules/jooby-undertow/pom.xml +++ b/modules/jooby-undertow/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-undertow jooby-undertow diff --git a/modules/jooby-vertx-mysql-client/pom.xml b/modules/jooby-vertx-mysql-client/pom.xml index 85fb616dd5..25b508d96f 100644 --- a/modules/jooby-vertx-mysql-client/pom.xml +++ b/modules/jooby-vertx-mysql-client/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-vertx-mysql-client jooby-vertx-mysql-client diff --git a/modules/jooby-vertx-pg-client/pom.xml b/modules/jooby-vertx-pg-client/pom.xml index 830464c8d3..0dc52d225f 100644 --- a/modules/jooby-vertx-pg-client/pom.xml +++ b/modules/jooby-vertx-pg-client/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-vertx-pg-client jooby-vertx-pg-client diff --git a/modules/jooby-vertx-sql-client/pom.xml b/modules/jooby-vertx-sql-client/pom.xml index 9ed175bec6..701e77e841 100644 --- a/modules/jooby-vertx-sql-client/pom.xml +++ b/modules/jooby-vertx-sql-client/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-vertx-sql-client jooby-vertx-sql-client diff --git a/modules/jooby-vertx/pom.xml b/modules/jooby-vertx/pom.xml index de8ff4d65b..5a431a84c6 100644 --- a/modules/jooby-vertx/pom.xml +++ b/modules/jooby-vertx/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-vertx jooby-vertx diff --git a/modules/jooby-whoops/pom.xml b/modules/jooby-whoops/pom.xml index 50dd0d1e9c..efe96f17fa 100644 --- a/modules/jooby-whoops/pom.xml +++ b/modules/jooby-whoops/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-whoops jooby-whoops diff --git a/modules/jooby-yasson/pom.xml b/modules/jooby-yasson/pom.xml index 7d52a6d236..8f7ba189c1 100644 --- a/modules/jooby-yasson/pom.xml +++ b/modules/jooby-yasson/pom.xml @@ -6,7 +6,7 @@ io.jooby modules - 4.2.0 + 4.3.0 jooby-yasson jooby-yasson diff --git a/modules/pom.xml b/modules/pom.xml index 8dc080e306..204d443c10 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -4,7 +4,7 @@ io.jooby jooby-project - 4.2.0 + 4.3.0 modules @@ -39,7 +39,18 @@ jooby-mcp jooby-mcp-jackson2 jooby-mcp-jackson3 + jooby-trpc-jackson2 + + jooby-trpc-jackson3 + jooby-trpc-avaje-jsonb jooby-trpc + jooby-trpc-generator + + jooby-jsonrpc-jackson2 + jooby-jsonrpc-jackson3 + jooby-jsonrpc-avaje-jsonb + jooby-jsonrpc + jooby-grpc diff --git a/pom.xml b/pom.xml index c1ecd90c78..edc632352b 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 io.jooby jooby-project - 4.2.0 + 4.3.0 pom jooby-project @@ -78,7 +78,7 @@ 3.52.0 11.20.1 25.0 - 7.5.0.RELEASE + 7.5.1.RELEASE 2.13.1 4.2.0 3.2.3 @@ -108,7 +108,7 @@ 2.4.0.RC4 - 12.1.7 + 12.1.8 4.2.12.Final 5.0.10 @@ -212,7 +212,7 @@ 21 21 yyyy-MM-dd HH:mm:ssa - 2026-03-31T14:15:44Z + 2026-04-08T14:58:58Z UTF-8 etc${file.separator}source${file.separator}formatter.sh @@ -1342,7 +1342,7 @@ org.apache.ant ant - 1.10.15 + 1.10.16 diff --git a/tests/pom.xml b/tests/pom.xml index 128cf7c0ff..843e04465f 100644 --- a/tests/pom.xml +++ b/tests/pom.xml @@ -6,7 +6,7 @@ io.jooby jooby-project - 4.2.0 + 4.3.0 tests tests @@ -161,6 +161,48 @@ jooby-mcp-jackson3 ${jooby.version} + + io.jooby + jooby-trpc + ${jooby.version} + + + io.jooby + jooby-trpc-jackson2 + ${jooby.version} + + + io.jooby + jooby-trpc-jackson3 + ${jooby.version} + + + io.jooby + jooby-trpc-avaje-jsonb + ${jooby.version} + + + + io.jooby + jooby-jsonrpc + ${jooby.version} + + + io.jooby + jooby-jsonrpc-jackson2 + ${jooby.version} + + + io.jooby + jooby-jsonrpc-jackson3 + ${jooby.version} + + + io.jooby + jooby-jsonrpc-avaje-jsonb + ${jooby.version} + + io.jooby jooby-test diff --git a/tests/src/test/java/examples/vertx/VertxPoolApp.java b/tests/src/test/java/examples/vertx/VertxPoolApp.java index 1cf340cac0..82a0fcf402 100644 --- a/tests/src/test/java/examples/vertx/VertxPoolApp.java +++ b/tests/src/test/java/examples/vertx/VertxPoolApp.java @@ -12,7 +12,7 @@ import com.typesafe.config.ConfigValueFactory; import io.jooby.ExecutionMode; import io.jooby.Jooby; -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; import io.jooby.vertx.VertxHandler; import io.jooby.vertx.VertxModule; import io.jooby.vertx.VertxServer; @@ -38,7 +38,7 @@ public class VertxPoolApp extends Jooby { .withValue( "db.password", ConfigValueFactory.fromAnyRef("benchmarkdbpass")))); - install(new JacksonModule()); + install(new Jackson2Module()); install(new VertxModule()); install(new VertxPgModule(PgBuilder::pool)); diff --git a/tests/src/test/java/io/jooby/i2413/Issue2413.java b/tests/src/test/java/io/jooby/i2413/Issue2413.java index 456966fea7..8ce1ac2c48 100644 --- a/tests/src/test/java/io/jooby/i2413/Issue2413.java +++ b/tests/src/test/java/io/jooby/i2413/Issue2413.java @@ -10,7 +10,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.xml.XmlMapper; import io.jooby.MediaType; -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; import io.jooby.junit.ServerTest; import io.jooby.junit.ServerTestRunner; import io.jooby.test.WebClient; @@ -21,9 +21,9 @@ public void shouldGenerateJsonAndXmlDefaultsJson(ServerTestRunner runner) { runner .define( app -> { - app.install(new JacksonModule(new ObjectMapper())); + app.install(new Jackson2Module(new ObjectMapper())); - app.install(new JacksonModule(new XmlMapper())); + app.install(new Jackson2Module(new XmlMapper())); app.get("/2413", ctx -> new B2413("someId", "someName")); }) @@ -92,9 +92,9 @@ public void shouldGenerateJsonAndXmlDefaultsXml(ServerTestRunner runner) { runner .define( app -> { - app.install(new JacksonModule(new XmlMapper(), MediaType.xml)); + app.install(new Jackson2Module(new XmlMapper(), MediaType.xml)); - app.install(new JacksonModule(new ObjectMapper())); + app.install(new Jackson2Module(new ObjectMapper())); app.get("/2413", ctx -> new B2413("someId", "someName")); }) diff --git a/tests/src/test/java/io/jooby/i2462/Issue2462.java b/tests/src/test/java/io/jooby/i2462/Issue2462.java index b36dd27bd4..abbe59728a 100644 --- a/tests/src/test/java/io/jooby/i2462/Issue2462.java +++ b/tests/src/test/java/io/jooby/i2462/Issue2462.java @@ -10,7 +10,7 @@ import java.util.Arrays; import io.jooby.ServerOptions; -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; import io.jooby.junit.ServerTest; import io.jooby.junit.ServerTestRunner; import io.jooby.test.WebClient; @@ -25,7 +25,7 @@ public void shouldSendMultipleMessageWithoutError(ServerTestRunner runner) { runner .define( app -> { - app.install(new JacksonModule()); + app.install(new Jackson2Module()); app.sse( "/2462", diff --git a/tests/src/test/java/io/jooby/i2525/Issue2525.java b/tests/src/test/java/io/jooby/i2525/Issue2525.java index 243a6a1a0c..7d12e2b885 100644 --- a/tests/src/test/java/io/jooby/i2525/Issue2525.java +++ b/tests/src/test/java/io/jooby/i2525/Issue2525.java @@ -7,7 +7,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; import io.jooby.junit.ServerTest; import io.jooby.junit.ServerTestRunner; @@ -17,7 +17,7 @@ public void shouldHandleMultipleAcceptHeaders(ServerTestRunner runner) { runner .define( app -> { - app.install(new JacksonModule()); + app.install(new Jackson2Module()); app.get( "/2525", ctx -> { diff --git a/tests/src/test/java/io/jooby/i2557/Issue2557.java b/tests/src/test/java/io/jooby/i2557/Issue2557.java index 703c1b33bf..2789dd1334 100644 --- a/tests/src/test/java/io/jooby/i2557/Issue2557.java +++ b/tests/src/test/java/io/jooby/i2557/Issue2557.java @@ -10,7 +10,7 @@ import java.util.UUID; -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; import io.jooby.junit.ServerTest; import io.jooby.junit.ServerTestRunner; import io.jooby.value.ConversionHint; @@ -28,7 +28,7 @@ public void shouldWorkWithEmptyUUID(ServerTestRunner runner) { runner .define( app -> { - app.install(new JacksonModule()); + app.install(new Jackson2Module()); app.post( "/2557/strict", diff --git a/tests/src/test/java/io/jooby/i2572/Issue2572.java b/tests/src/test/java/io/jooby/i2572/Issue2572.java index 3af9326b40..440dc98db0 100644 --- a/tests/src/test/java/io/jooby/i2572/Issue2572.java +++ b/tests/src/test/java/io/jooby/i2572/Issue2572.java @@ -13,7 +13,7 @@ import org.json.JSONObject; -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; import io.jooby.junit.ServerTest; import io.jooby.junit.ServerTestRunner; @@ -27,7 +27,7 @@ public void onCompleteShouldRunOnCallerThread(ServerTestRunner runner) { Map state = new ConcurrentHashMap<>(); CountDownLatch latch = new CountDownLatch(1); - app.install(new JacksonModule()); + app.install(new Jackson2Module()); app.get( "/2572/state", diff --git a/tests/src/test/java/io/jooby/i2613/Issue2613.java b/tests/src/test/java/io/jooby/i2613/Issue2613.java index ddd458e005..a3bb38b072 100644 --- a/tests/src/test/java/io/jooby/i2613/Issue2613.java +++ b/tests/src/test/java/io/jooby/i2613/Issue2613.java @@ -14,7 +14,7 @@ import io.jooby.Context; import io.jooby.MediaType; import io.jooby.MessageEncoder; -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; import io.jooby.junit.ServerTest; import io.jooby.junit.ServerTestRunner; import io.jooby.output.Output; @@ -46,7 +46,7 @@ public void shouldConsiderRouteProduces(ServerTestRunner runner) { .define( app -> { app.encoder(MediaType.html, new ThemeResultEncoder()); - app.install(new JacksonModule()); + app.install(new Jackson2Module()); app.get("/2613/json", ctx -> ImmutableMap.of("foo", "bar")).produces(MediaType.json); }) diff --git a/tests/src/test/java/io/jooby/i2806/Issue2806.java b/tests/src/test/java/io/jooby/i2806/Issue2806.java index dc60183d31..7aeab8cdd5 100644 --- a/tests/src/test/java/io/jooby/i2806/Issue2806.java +++ b/tests/src/test/java/io/jooby/i2806/Issue2806.java @@ -12,7 +12,7 @@ import com.google.common.collect.ImmutableMap; import io.jooby.ServerOptions; -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; import io.jooby.junit.ServerTest; import io.jooby.junit.ServerTestRunner; import io.jooby.output.OutputOptions; @@ -30,7 +30,7 @@ public void renderShouldWorkFromErrorHandlerWhenLargeRequestAreSent(ServerTestRu .setMaxRequestSize(ServerOptions._16KB)) .define( app -> { - app.install(new JacksonModule()); + app.install(new Jackson2Module()); app.error( (ctx, cause, code) -> { diff --git a/tests/src/test/java/io/jooby/i2818/Issue2818.java b/tests/src/test/java/io/jooby/i2818/Issue2818.java index 0ed49989ea..7eeb3abc37 100644 --- a/tests/src/test/java/io/jooby/i2818/Issue2818.java +++ b/tests/src/test/java/io/jooby/i2818/Issue2818.java @@ -10,7 +10,7 @@ import java.nio.charset.StandardCharsets; import java.util.Map; -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; import io.jooby.junit.ServerTest; import io.jooby.junit.ServerTestRunner; @@ -117,7 +117,7 @@ public void shouldRenderBinary(ServerTestRunner runner) { runner .define( app -> { - app.install(new JacksonModule()); + app.install(new Jackson2Module()); app.ws( "/ws/render-bin", (ctx, initializer) -> { @@ -139,7 +139,7 @@ public void shouldBroadcastRenderBinary(ServerTestRunner runner) { runner .define( app -> { - app.install(new JacksonModule()); + app.install(new Jackson2Module()); app.ws( "/ws/render-bin", (ctx, initializer) -> { diff --git a/tests/src/test/java/io/jooby/i2923/Issue2923.java b/tests/src/test/java/io/jooby/i2923/Issue2923.java index e725c5e867..93d126e036 100644 --- a/tests/src/test/java/io/jooby/i2923/Issue2923.java +++ b/tests/src/test/java/io/jooby/i2923/Issue2923.java @@ -7,7 +7,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; import io.jooby.junit.ServerTest; import io.jooby.junit.ServerTestRunner; @@ -18,7 +18,7 @@ public void shouldParseJavaRecord(ServerTestRunner runner) { runner .define( app -> { - app.install(new JacksonModule()); + app.install(new Jackson2Module()); app.get( "/2923", ctx -> { diff --git a/tests/src/test/java/io/jooby/i3400/Issue3400.java b/tests/src/test/java/io/jooby/i3400/Issue3400.java index 7cd0e8baf7..c5c1cca805 100644 --- a/tests/src/test/java/io/jooby/i3400/Issue3400.java +++ b/tests/src/test/java/io/jooby/i3400/Issue3400.java @@ -8,7 +8,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import io.jooby.Jooby; -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; import io.jooby.junit.ServerTest; import io.jooby.junit.ServerTestRunner; import okhttp3.MediaType; @@ -27,7 +27,7 @@ public void shouldShareDecodersOnMountedResources(ServerTestRunner runner) { runner .define( app -> { - app.install(new JacksonModule()); + app.install(new Jackson2Module()); app.mount(new AppA()); }) .ready( @@ -48,7 +48,7 @@ public void shouldShareDecodersOnInstalledResources(ServerTestRunner runner) { runner .define( app -> { - app.install(new JacksonModule()); + app.install(new Jackson2Module()); app.install(AppA::new); }) .ready( diff --git a/tests/src/test/java/io/jooby/i3479/Issue3479.java b/tests/src/test/java/io/jooby/i3479/Issue3479.java index dc3f77f327..0392497531 100644 --- a/tests/src/test/java/io/jooby/i3479/Issue3479.java +++ b/tests/src/test/java/io/jooby/i3479/Issue3479.java @@ -7,7 +7,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; import io.jooby.junit.ServerTest; import io.jooby.junit.ServerTestRunner; @@ -21,7 +21,7 @@ public void shouldRespectLeadingWhiteSpace(ServerTestRunner runner) { runner .define( app -> { - app.install(new JacksonModule()); + app.install(new Jackson2Module()); app.sse( "/3479", diff --git a/tests/src/test/java/io/jooby/i3508/App3508.java b/tests/src/test/java/io/jooby/i3508/App3508.java index 0e2cf3cf69..0504225d13 100644 --- a/tests/src/test/java/io/jooby/i3508/App3508.java +++ b/tests/src/test/java/io/jooby/i3508/App3508.java @@ -11,7 +11,7 @@ import com.typesafe.config.ConfigFactory; import io.jooby.Extension; import io.jooby.Jooby; -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; public class App3508 extends Jooby { public App3508(Extension validator, boolean withProblemDetails) { @@ -24,7 +24,7 @@ public App3508(Extension validator, boolean withProblemDetails) { getEnvironment().setConfig(problemDetailsConfig.withFallback(getConfig())); } - install(new JacksonModule()); + install(new Jackson2Module()); install(validator); mvc(new Controller3508_()); diff --git a/tests/src/test/java/io/jooby/i3508/Issue3508.java b/tests/src/test/java/io/jooby/i3508/Issue3508.java index a4c628e7c9..e0cf198613 100644 --- a/tests/src/test/java/io/jooby/i3508/Issue3508.java +++ b/tests/src/test/java/io/jooby/i3508/Issue3508.java @@ -24,7 +24,7 @@ import io.jooby.i3508.data.HbvNewAccountRequest; import io.jooby.i3508.data.NewAccountRequest; import io.jooby.i3508.data.Person; -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; import io.jooby.junit.ServerTest; import io.jooby.junit.ServerTestRunner; import io.jooby.validation.BeanValidator; @@ -41,7 +41,7 @@ public void shouldValidateUsingProxy(ServerTestRunner runner) { runner .define( app -> { - app.install(new JacksonModule()); + app.install(new Jackson2Module()); app.install(new HibernateValidatorModule()); app.get("/3508/query", validate(ctx -> ctx.query().to(Bean3508.class))); diff --git a/tests/src/test/java/io/jooby/i3530/Issue3530.java b/tests/src/test/java/io/jooby/i3530/Issue3530.java index 3c223f52cb..69287228c2 100644 --- a/tests/src/test/java/io/jooby/i3530/Issue3530.java +++ b/tests/src/test/java/io/jooby/i3530/Issue3530.java @@ -9,7 +9,7 @@ import io.jooby.StatusCode; import io.jooby.hibernate.validator.HibernateValidatorModule; -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; import io.jooby.junit.ServerTest; import io.jooby.junit.ServerTestRunner; import io.jooby.validation.BeanValidator; @@ -24,7 +24,7 @@ public void shouldRunValidationOnce(ServerTestRunner runner) { runner .define( app -> { - app.install(new JacksonModule()); + app.install(new Jackson2Module()); app.install(new HibernateValidatorModule()); app.use(BeanValidator.validate()); diff --git a/tests/src/test/java/io/jooby/i3551/Issue3551.java b/tests/src/test/java/io/jooby/i3551/Issue3551.java index b5b3e102c3..fe1f4e3f4f 100644 --- a/tests/src/test/java/io/jooby/i3551/Issue3551.java +++ b/tests/src/test/java/io/jooby/i3551/Issue3551.java @@ -11,7 +11,7 @@ import io.jooby.ServiceKey; import io.jooby.StatusCode; import io.jooby.guice.GuiceModule; -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; import io.jooby.junit.ServerTest; import io.jooby.junit.ServerTestRunner; @@ -25,7 +25,7 @@ public void shouldEnsureDIOnStartCallbacks(ServerTestRunner runner) { .put( ServiceKey.key(Service3551.class, "service"), new Service3551(app.getEnvironment())); - app.install(new JacksonModule().module(JacksonModule3551.class)); + app.install(new Jackson2Module().module(JacksonModule3551.class)); app.install(new GuiceModule()); diff --git a/tests/src/test/java/io/jooby/i3751/Issue3751.java b/tests/src/test/java/io/jooby/i3751/Issue3751.java index 75f0d95fd8..066238b81c 100644 --- a/tests/src/test/java/io/jooby/i3751/Issue3751.java +++ b/tests/src/test/java/io/jooby/i3751/Issue3751.java @@ -10,7 +10,7 @@ import java.util.List; import io.jooby.hibernate.validator.HibernateValidatorModule; -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; import io.jooby.junit.ServerTest; import io.jooby.junit.ServerTestRunner; import io.jooby.validation.BeanValidator; @@ -25,7 +25,7 @@ public void shouldValidateDataBody(ServerTestRunner runner) { .define( app -> { app.install(new HibernateValidatorModule()); - app.install(new JacksonModule()); + app.install(new Jackson2Module()); app.post( "/3751-direct", (ctx -> { diff --git a/tests/src/test/java/io/jooby/i3778/Issue3778.java b/tests/src/test/java/io/jooby/i3778/Issue3778.java index 38f7b3200f..82809e06a8 100644 --- a/tests/src/test/java/io/jooby/i3778/Issue3778.java +++ b/tests/src/test/java/io/jooby/i3778/Issue3778.java @@ -16,7 +16,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.jooby.ExecutionMode; -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; import io.jooby.junit.ServerTest; import io.jooby.junit.ServerTestRunner; import io.jooby.vertx.VertxModule; @@ -48,7 +48,7 @@ private void shouldHandleVertxReactiveResponse(ServerTestRunner runner, boolean if (!onVertx) { app.install(new VertxModule(new VertxOptions().setEventLoopPoolSize(4))); } - app.install(new JacksonModule()); + app.install(new Jackson2Module()); app.use(vertx()); diff --git a/tests/src/test/java/io/jooby/i3830/UserToolsTest.java b/tests/src/test/java/io/jooby/i3830/UserToolsTest.java index 9d06b2bf95..08afc2d823 100644 --- a/tests/src/test/java/io/jooby/i3830/UserToolsTest.java +++ b/tests/src/test/java/io/jooby/i3830/UserToolsTest.java @@ -12,7 +12,7 @@ import io.jooby.Extension; import io.jooby.Jooby; import io.jooby.SneakyThrows; -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; import io.jooby.jackson3.Jackson3Module; import io.jooby.junit.ServerTest; import io.jooby.junit.ServerTestRunner; @@ -36,7 +36,7 @@ private void setupMcpApp(Jooby app, Extension... extensions) { @ServerTest public void shouldReturnStructuredJsonObjectOnJackson2(ServerTestRunner runner) { runner - .define(app -> setupMcpApp(app, new JacksonModule(), new McpJackson2Module())) + .define(app -> setupMcpApp(app, new Jackson2Module(), new McpJackson2Module())) .ready(assertStructuredJson()); } diff --git a/tests/src/test/java/io/jooby/i3853/Issue3853.java b/tests/src/test/java/io/jooby/i3853/Issue3853.java index 62e663d8a0..061dc717d5 100644 --- a/tests/src/test/java/io/jooby/i3853/Issue3853.java +++ b/tests/src/test/java/io/jooby/i3853/Issue3853.java @@ -14,7 +14,7 @@ import io.jooby.Projected; import io.jooby.Projection; import io.jooby.avaje.jsonb.AvajeJsonbModule; -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; import io.jooby.jackson3.Jackson3Module; import io.jooby.junit.ServerTest; import io.jooby.junit.ServerTestRunner; @@ -25,7 +25,7 @@ public class Issue3853 { @ServerTest public void shouldProjectJackson2Data(ServerTestRunner runner) { - shouldProjectData(runner, new JacksonModule()); + shouldProjectData(runner, new Jackson2Module()); } @ServerTest @@ -205,7 +205,7 @@ public void shouldProjectData(ServerTestRunner runner, Extension extension) { @ServerTest public void jackson2ShouldNotThrowInvalidDefinitionException(ServerTestRunner runner) { - jacksonShouldNotThrowInvalidDefinitionException(runner, new JacksonModule()); + jacksonShouldNotThrowInvalidDefinitionException(runner, new Jackson2Module()); } @ServerTest diff --git a/tests/src/test/java/io/jooby/i3853/Issue3853Mvc.java b/tests/src/test/java/io/jooby/i3853/Issue3853Mvc.java index b563a088dd..c3bb4b1cf5 100644 --- a/tests/src/test/java/io/jooby/i3853/Issue3853Mvc.java +++ b/tests/src/test/java/io/jooby/i3853/Issue3853Mvc.java @@ -9,7 +9,7 @@ import io.jooby.Extension; import io.jooby.avaje.jsonb.AvajeJsonbModule; -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; import io.jooby.jackson3.Jackson3Module; import io.jooby.junit.ServerTest; import io.jooby.junit.ServerTestRunner; @@ -18,7 +18,7 @@ public class Issue3853Mvc { @ServerTest public void shouldProjectJackson2Data(ServerTestRunner runner) { - shouldProjectData(runner, new JacksonModule()); + shouldProjectData(runner, new Jackson2Module()); } @ServerTest diff --git a/tests/src/test/java/io/jooby/i3863/AbstractTrpcProtocolTest.java b/tests/src/test/java/io/jooby/i3863/AbstractTrpcProtocolTest.java index 3e1f5c8991..787e9d6bb7 100644 --- a/tests/src/test/java/io/jooby/i3863/AbstractTrpcProtocolTest.java +++ b/tests/src/test/java/io/jooby/i3863/AbstractTrpcProtocolTest.java @@ -13,7 +13,7 @@ import io.jooby.Jooby; import io.jooby.junit.ServerTest; import io.jooby.junit.ServerTestRunner; -import io.jooby.rpc.trpc.TrpcModule; +import io.jooby.trpc.TrpcModule; public abstract class AbstractTrpcProtocolTest { @@ -26,8 +26,7 @@ public abstract class AbstractTrpcProtocolTest { // Helper to keep test setup DRY private void setupApp(Jooby app) { installJsonEngine(app); - app.install(new TrpcModule()); - app.trpc(new MovieServiceTrpc_()); + app.install(new TrpcModule(new MovieServiceTsTrpc_())); } @ServerTest diff --git a/tests/src/test/java/io/jooby/i3863/AvajeTrpcProtocolTest.java b/tests/src/test/java/io/jooby/i3863/AvajeTrpcProtocolTest.java index 5fe78d9de0..ee8fec0f51 100644 --- a/tests/src/test/java/io/jooby/i3863/AvajeTrpcProtocolTest.java +++ b/tests/src/test/java/io/jooby/i3863/AvajeTrpcProtocolTest.java @@ -7,10 +7,12 @@ import io.jooby.Jooby; import io.jooby.avaje.jsonb.AvajeJsonbModule; +import io.jooby.trpc.avaje.jsonb.TrpcAvajeJsonbModule; public class AvajeTrpcProtocolTest extends AbstractTrpcProtocolTest { @Override protected void installJsonEngine(Jooby app) { app.install(new AvajeJsonbModule()); + app.install(new TrpcAvajeJsonbModule()); } } diff --git a/tests/src/test/java/io/jooby/i3863/Jackson2TrpcProtocolTest.java b/tests/src/test/java/io/jooby/i3863/Jackson2TrpcProtocolTest.java index 8e90d41c14..b4596c2695 100644 --- a/tests/src/test/java/io/jooby/i3863/Jackson2TrpcProtocolTest.java +++ b/tests/src/test/java/io/jooby/i3863/Jackson2TrpcProtocolTest.java @@ -6,11 +6,13 @@ package io.jooby.i3863; import io.jooby.Jooby; -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; +import io.jooby.trpc.jackson2.TrpcJackson2Module; public class Jackson2TrpcProtocolTest extends AbstractTrpcProtocolTest { @Override protected void installJsonEngine(Jooby app) { - app.install(new JacksonModule()); + app.install(new Jackson2Module()); + app.install(new TrpcJackson2Module()); } } diff --git a/tests/src/test/java/io/jooby/i3863/Jackson3TrpcProtocolTest.java b/tests/src/test/java/io/jooby/i3863/Jackson3TrpcProtocolTest.java index f5dad5f885..6a16ac7c44 100644 --- a/tests/src/test/java/io/jooby/i3863/Jackson3TrpcProtocolTest.java +++ b/tests/src/test/java/io/jooby/i3863/Jackson3TrpcProtocolTest.java @@ -7,10 +7,12 @@ import io.jooby.Jooby; import io.jooby.jackson3.Jackson3Module; +import io.jooby.trpc.jackson3.TrpcJackson3Module; public class Jackson3TrpcProtocolTest extends AbstractTrpcProtocolTest { @Override protected void installJsonEngine(Jooby app) { app.install(new Jackson3Module()); + app.install(new TrpcJackson3Module()); } } diff --git a/tests/src/test/java/io/jooby/i3863/MovieService.java b/tests/src/test/java/io/jooby/i3863/MovieServiceTs.java similarity index 97% rename from tests/src/test/java/io/jooby/i3863/MovieService.java rename to tests/src/test/java/io/jooby/i3863/MovieServiceTs.java index 55e00837db..964a269ac5 100644 --- a/tests/src/test/java/io/jooby/i3863/MovieService.java +++ b/tests/src/test/java/io/jooby/i3863/MovieServiceTs.java @@ -11,12 +11,13 @@ import edu.umd.cs.findbugs.annotations.NonNull; import io.jooby.annotation.*; +import io.jooby.annotation.trpc.Trpc; import io.jooby.exception.NotFoundException; import reactor.core.publisher.Mono; @Trpc("movies") @Path("/api/movies") -public class MovieService { +public class MovieServiceTs { private final List database = List.of(new Movie(1, "The Godfather", 1972), new Movie(2, "Pulp Fiction", 1994)); diff --git a/tests/src/test/java/io/jooby/i3868/AbstractJsonRpcProtocolTest.java b/tests/src/test/java/io/jooby/i3868/AbstractJsonRpcProtocolTest.java index af9edcffc3..941e07b078 100644 --- a/tests/src/test/java/io/jooby/i3868/AbstractJsonRpcProtocolTest.java +++ b/tests/src/test/java/io/jooby/i3868/AbstractJsonRpcProtocolTest.java @@ -12,6 +12,7 @@ import com.jayway.jsonpath.JsonPath; import io.jooby.Jooby; +import io.jooby.jsonrpc.JsonRpcModule; import io.jooby.junit.ServerTest; import io.jooby.junit.ServerTestRunner; @@ -25,7 +26,8 @@ public abstract class AbstractJsonRpcProtocolTest { // Helper to keep test setup DRY private void setupApp(Jooby app) { installJsonEngine(app); - app.mvc(new MovieService_()); + app.install(new JsonRpcModule(new MovieServiceRpcRpc_())); + app.mvc(new MovieServiceRpc_()); } diff --git a/tests/src/test/java/io/jooby/i3868/AvajeJsonRpcProtocolTest.java b/tests/src/test/java/io/jooby/i3868/AvajeJsonRpcProtocolTest.java index bafad8410f..257ba8546b 100644 --- a/tests/src/test/java/io/jooby/i3868/AvajeJsonRpcProtocolTest.java +++ b/tests/src/test/java/io/jooby/i3868/AvajeJsonRpcProtocolTest.java @@ -7,10 +7,12 @@ import io.jooby.Jooby; import io.jooby.avaje.jsonb.AvajeJsonbModule; +import io.jooby.jsonrpc.avaje.jsonb.JsonRpcAvajeJsonbModule; public class AvajeJsonRpcProtocolTest extends AbstractJsonRpcProtocolTest { @Override protected void installJsonEngine(Jooby app) { app.install(new AvajeJsonbModule()); + app.install(new JsonRpcAvajeJsonbModule()); } } diff --git a/tests/src/test/java/io/jooby/i3868/Jackson2JsonRpcProtocolTest.java b/tests/src/test/java/io/jooby/i3868/Jackson2JsonRpcProtocolTest.java index 0b8d6d6e9b..1060b4013a 100644 --- a/tests/src/test/java/io/jooby/i3868/Jackson2JsonRpcProtocolTest.java +++ b/tests/src/test/java/io/jooby/i3868/Jackson2JsonRpcProtocolTest.java @@ -6,11 +6,13 @@ package io.jooby.i3868; import io.jooby.Jooby; -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; +import io.jooby.jsonrpc.jackson2.JsonRpcJackson2Module; public class Jackson2JsonRpcProtocolTest extends AbstractJsonRpcProtocolTest { @Override protected void installJsonEngine(Jooby app) { - app.install(new JacksonModule()); + app.install(new Jackson2Module()); + app.install(new JsonRpcJackson2Module()); } } diff --git a/tests/src/test/java/io/jooby/i3868/Jackson3JsonRpcProtocolTest.java b/tests/src/test/java/io/jooby/i3868/Jackson3JsonRpcProtocolTest.java index f2b766aa18..45bfd7d482 100644 --- a/tests/src/test/java/io/jooby/i3868/Jackson3JsonRpcProtocolTest.java +++ b/tests/src/test/java/io/jooby/i3868/Jackson3JsonRpcProtocolTest.java @@ -7,10 +7,12 @@ import io.jooby.Jooby; import io.jooby.jackson3.Jackson3Module; +import io.jooby.jsonrpc.jackson3.JsonRpcJackson3Module; public class Jackson3JsonRpcProtocolTest extends AbstractJsonRpcProtocolTest { @Override protected void installJsonEngine(Jooby app) { app.install(new Jackson3Module()); + app.install(new JsonRpcJackson3Module()); } } diff --git a/tests/src/test/java/io/jooby/i3868/MovieService.java b/tests/src/test/java/io/jooby/i3868/MovieServiceRpc.java similarity index 93% rename from tests/src/test/java/io/jooby/i3868/MovieService.java rename to tests/src/test/java/io/jooby/i3868/MovieServiceRpc.java index 5c5ba7b266..f61abf9690 100644 --- a/tests/src/test/java/io/jooby/i3868/MovieService.java +++ b/tests/src/test/java/io/jooby/i3868/MovieServiceRpc.java @@ -9,19 +9,19 @@ import edu.umd.cs.findbugs.annotations.NonNull; import io.jooby.annotation.*; +import io.jooby.annotation.jsonrpc.JsonRpc; import io.jooby.exception.NotFoundException; import io.jooby.i3863.Movie; @JsonRpc("movies") @Path("/api/movies") -public class MovieService { +public class MovieServiceRpc { private final List database = List.of(new Movie(1, "The Godfather", 1972), new Movie(2, "Pulp Fiction", 1994)); /** Procedure: movies.create Takes a single complex object. */ @POST - @Trpc public Movie create(Movie movie) { // In a real app, save to DB. For now, just return it. return movie; diff --git a/tests/src/test/java/io/jooby/problem/data/App.java b/tests/src/test/java/io/jooby/problem/data/App.java index 44833ad3ae..62521fb54e 100644 --- a/tests/src/test/java/io/jooby/problem/data/App.java +++ b/tests/src/test/java/io/jooby/problem/data/App.java @@ -17,7 +17,7 @@ import io.jooby.StatusCode; import io.jooby.exception.InvalidCsrfToken; import io.jooby.exception.StatusCodeException; -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; import io.jooby.problem.HttpProblem; public class App extends Jooby { @@ -36,7 +36,7 @@ public class App extends Jooby { List.of("io.jooby.exception.UnauthorizedException"))); getEnvironment().setConfig(problemDetailsConfig.withFallback(getConfig())); - install(new JacksonModule()); + install(new Jackson2Module()); get( "/throw-simple-http-problem", diff --git a/tests/src/test/java/io/jooby/test/FeaturedTest.java b/tests/src/test/java/io/jooby/test/FeaturedTest.java index 84352b972f..ab5ed8eaba 100644 --- a/tests/src/test/java/io/jooby/test/FeaturedTest.java +++ b/tests/src/test/java/io/jooby/test/FeaturedTest.java @@ -66,7 +66,7 @@ import io.jooby.handler.HeadHandler; import io.jooby.handler.TraceHandler; import io.jooby.handler.WebVariables; -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; import io.jooby.jackson3.Jackson3Module; import io.jooby.junit.ServerTest; import io.jooby.junit.ServerTestRunner; @@ -3044,7 +3044,7 @@ public void render(ServerTestRunner runner) { runner .define( app -> { - app.install(new JacksonModule()); + app.install(new Jackson2Module()); app.get("/int", ctx -> ctx.render(1)); app.get("/bytes", ctx -> ctx.render("bytes".getBytes(StandardCharsets.UTF_8))); app.get( @@ -3674,7 +3674,7 @@ public void head(ServerTestRunner runner) { runner .define( app -> { - app.install(new JacksonModule()); + app.install(new Jackson2Module()); app.use(new HeadHandler()); app.get("/fn", ctx -> "string"); @@ -3984,7 +3984,7 @@ public void errorOnParsingFormUrlEncoded(ServerTestRunner runner) { runner .define( app -> { - app.install(new JacksonModule()); + app.install(new Jackson2Module()); app.post( "/", diff --git a/tests/src/test/java/io/jooby/test/Http2Test.java b/tests/src/test/java/io/jooby/test/Http2Test.java index 89796b2e35..54b37e82df 100644 --- a/tests/src/test/java/io/jooby/test/Http2Test.java +++ b/tests/src/test/java/io/jooby/test/Http2Test.java @@ -31,7 +31,7 @@ import com.google.common.collect.ImmutableMap; import io.jooby.*; -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; import io.jooby.junit.ServerTest; import io.jooby.junit.ServerTestRunner; import okhttp3.*; @@ -45,7 +45,7 @@ public void h2body(ServerTestRunner runner) { .options(new ServerOptions().setHttp2(true)) .define( app -> { - app.install(new JacksonModule()); + app.install(new Jackson2Module()); app.post( "/h2/multipart", ctx -> { diff --git a/tests/src/test/java/io/jooby/test/Issue1391.java b/tests/src/test/java/io/jooby/test/Issue1391.java index 3cb6d1bd7b..11316cfd0f 100644 --- a/tests/src/test/java/io/jooby/test/Issue1391.java +++ b/tests/src/test/java/io/jooby/test/Issue1391.java @@ -7,7 +7,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; import io.jooby.junit.ServerTest; import io.jooby.junit.ServerTestRunner; import okhttp3.MediaType; @@ -20,7 +20,7 @@ public void issue1391(ServerTestRunner runner) { runner .define( app -> { - app.install(new JacksonModule()); + app.install(new Jackson2Module()); app.mvc(new Controller1391_()); }) .ready( diff --git a/tests/src/test/java/io/jooby/test/MvcTest.java b/tests/src/test/java/io/jooby/test/MvcTest.java index 8b4d418a10..a58c39eefc 100644 --- a/tests/src/test/java/io/jooby/test/MvcTest.java +++ b/tests/src/test/java/io/jooby/test/MvcTest.java @@ -19,7 +19,7 @@ import io.jooby.ExecutionMode; import io.jooby.Jooby; import io.jooby.MessageDecoder; -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; import io.jooby.junit.ServerTest; import io.jooby.junit.ServerTestRunner; import okhttp3.FormBody; @@ -470,7 +470,7 @@ public void mvcBody(ServerTestRunner runner) { runner .define( app -> { - app.install(new JacksonModule()); + app.install(new Jackson2Module()); app.mvc(new MvcBody_()); diff --git a/tests/src/test/java/io/jooby/test/ServerSentEventTest.java b/tests/src/test/java/io/jooby/test/ServerSentEventTest.java index 64301d00a1..a9aeaf4316 100644 --- a/tests/src/test/java/io/jooby/test/ServerSentEventTest.java +++ b/tests/src/test/java/io/jooby/test/ServerSentEventTest.java @@ -22,7 +22,7 @@ import io.jooby.ExecutionMode; import io.jooby.ServerSentMessage; -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; import io.jooby.junit.ServerTest; import io.jooby.junit.ServerTestRunner; @@ -32,7 +32,7 @@ public void shouldSupportsSse(ServerTestRunner runner) { runner .define( app -> { - app.install(new JacksonModule()); + app.install(new Jackson2Module()); app.sse( "/", @@ -85,7 +85,7 @@ public void shouldUseEncoder(ServerTestRunner runner) { runner .define( app -> { - app.install(new JacksonModule()); + app.install(new Jackson2Module()); app.sse( "/json", @@ -113,7 +113,7 @@ public void shouldWorkWithEventType(ServerTestRunner runner) { runner .define( app -> { - app.install(new JacksonModule()); + app.install(new Jackson2Module()); app.sse( "/event-type", @@ -170,7 +170,7 @@ public void shouldWorkWithMultilineMessages(ServerTestRunner runner) { runner .define( app -> { - app.install(new JacksonModule()); + app.install(new Jackson2Module()); app.sse( "/multi-line", diff --git a/tests/src/test/java/io/jooby/test/WebSocketTest.java b/tests/src/test/java/io/jooby/test/WebSocketTest.java index 2e64bcbdab..9dc18951fd 100644 --- a/tests/src/test/java/io/jooby/test/WebSocketTest.java +++ b/tests/src/test/java/io/jooby/test/WebSocketTest.java @@ -10,7 +10,7 @@ import java.nio.charset.StandardCharsets; import com.fasterxml.jackson.databind.JsonNode; -import io.jooby.jackson.JacksonModule; +import io.jooby.jackson.Jackson2Module; import io.jooby.junit.ServerTest; import io.jooby.junit.ServerTestRunner; @@ -120,7 +120,7 @@ public void webSocketJson(ServerTestRunner runner) { runner .define( app -> { - app.install(new JacksonModule()); + app.install(new Jackson2Module()); app.ws( "/wsjson", diff --git a/tests/src/test/kotlin/i3476/Issue3476.kt b/tests/src/test/kotlin/i3476/Issue3476.kt index f0487cc0c7..2779711e9b 100644 --- a/tests/src/test/kotlin/i3476/Issue3476.kt +++ b/tests/src/test/kotlin/i3476/Issue3476.kt @@ -5,7 +5,7 @@ */ package i3476 -import io.jooby.jackson.JacksonModule +import io.jooby.jackson.Jackson2Module import io.jooby.junit.ServerTest import io.jooby.junit.ServerTestRunner import io.jooby.kt.Kooby @@ -17,7 +17,7 @@ class Issue3476 { runner .use { Kooby { - install(JacksonModule()) + install(Jackson2Module()) mvc(C3476_()) } } diff --git a/tests/src/test/kotlin/i3477/Issue3477.kt b/tests/src/test/kotlin/i3477/Issue3477.kt index de41772092..44c2f597a9 100644 --- a/tests/src/test/kotlin/i3477/Issue3477.kt +++ b/tests/src/test/kotlin/i3477/Issue3477.kt @@ -5,7 +5,7 @@ */ package i3477 -import io.jooby.jackson.JacksonModule +import io.jooby.jackson.Jackson2Module import io.jooby.junit.ServerTest import io.jooby.junit.ServerTestRunner import io.jooby.kt.Kooby @@ -17,7 +17,7 @@ class Issue3477 { runner .use { Kooby { - install(JacksonModule()) + install(Jackson2Module()) mvc(C3477_()) } } diff --git a/tests/src/test/kotlin/i3863/KMovieService.kt b/tests/src/test/kotlin/i3863/KMovieService.kt index 2f6de68d1f..3ed750a96d 100644 --- a/tests/src/test/kotlin/i3863/KMovieService.kt +++ b/tests/src/test/kotlin/i3863/KMovieService.kt @@ -5,8 +5,7 @@ */ package i3863 -import io.jooby.annotation.Trpc -import io.jooby.annotation.Trpc.Mutation +import io.jooby.annotation.trpc.Trpc import io.jooby.i3863.Metadata import io.jooby.i3863.Movie import java.util.stream.Collectors @@ -17,13 +16,13 @@ class KMovieService { listOf(Movie(1, "The Godfather", 1972), Movie(2, "Pulp Fiction", 1994)) /** Procedure: movies.create Takes a single complex object. */ - @Mutation + @Trpc.Mutation fun create(movie: Movie?): Movie? { // In a real app, save to DB. For now, just return it. return movie } - @Mutation fun resetIndex() {} + @Trpc.Mutation fun resetIndex() {} /** Procedure: movies.bulkCreate Takes a List of complex objects. */ @Trpc.Query @@ -56,14 +55,14 @@ class KMovieService { } /** Procedure: movies.addReview Mix of String and int (Mutation) */ - @Mutation + @Trpc.Mutation fun addReview(movieTitle: String, stars: Int, comment: String?): Map { // Business logic... return mapOf("title" to movieTitle, "rating" to stars, "status" to "published") } /** Procedure: movies.addReview Mix of String and int (Mutation) */ - @Mutation + @Trpc.Mutation fun updateMetadata(id: Int, metadata: Metadata?): Metadata? { // Business logic... return metadata diff --git a/tests/src/test/kotlin/i3868/KtMovieService.kt b/tests/src/test/kotlin/i3868/KtMovieServiceRpc.kt similarity index 92% rename from tests/src/test/kotlin/i3868/KtMovieService.kt rename to tests/src/test/kotlin/i3868/KtMovieServiceRpc.kt index 2bd8888185..26a81c0d50 100644 --- a/tests/src/test/kotlin/i3868/KtMovieService.kt +++ b/tests/src/test/kotlin/i3868/KtMovieServiceRpc.kt @@ -6,19 +6,20 @@ package i3868 import io.jooby.annotation.* +import io.jooby.annotation.jsonrpc.JsonRpc import io.jooby.exception.NotFoundException import io.jooby.i3863.Movie import java.util.function.Supplier @JsonRpc("movies") @Path("/api/movies") -class KtMovieService { +class KtMovieServiceRpc { private val database: List = listOf(Movie(1, "The Godfather", 1972), Movie(2, "Pulp Fiction", 1994)) /** Procedure: movies.create Takes a single complex object. */ @POST - @Trpc + @JsonRpc fun create(movie: Movie): Movie { // In a real app, save to DB. For now, just return it. return movie diff --git a/tests/src/test/kotlin/io/jooby/FeaturedKotlinTest.kt b/tests/src/test/kotlin/io/jooby/FeaturedKotlinTest.kt index a9faf595f3..b064ec3c1f 100644 --- a/tests/src/test/kotlin/io/jooby/FeaturedKotlinTest.kt +++ b/tests/src/test/kotlin/io/jooby/FeaturedKotlinTest.kt @@ -6,7 +6,7 @@ package io.jooby import io.jooby.internal.mvc.KotlinMvc_ -import io.jooby.jackson.JacksonModule +import io.jooby.jackson.Jackson2Module import io.jooby.junit.ServerTest import io.jooby.junit.ServerTestRunner import io.jooby.kt.Kooby @@ -150,7 +150,7 @@ class FeaturedKotlinTest { runner .use { -> Kooby { - install(JacksonModule()) + install(Jackson2Module()) use { RequestScope.bind("key", UUID.randomUUID().toString())