|
| 1 | +# Vert.x Mutiny bindings generator migration guide |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +As stated in the [vertx mutiny bindings generator guide](https://smallrye.io/smallrye-mutiny-vertx-bindings/latest/): |
| 6 | +> [Eclipse Vert.x](https://vertx.io/) is the leading toolkit for writing reactive applications on the JVM. |
| 7 | +> |
| 8 | +> While the Vert.x core APIs expose asynchronous programming through _promise / future_, code generators offer bindings to other asynchronous programming models, including: [Kotlin coroutines](https://github.com/vert-x3/vertx-lang-kotlin/tree/master/vertx-lang-kotlin-coroutines), and [RxJava 1, 2 and 3](https://github.com/vert-x3/vertx-rx). |
| 9 | +> |
| 10 | +> This project offers [Vert.x](https://vertx.io/) binding for [Mutiny, an intuitive event-driven reactive programming library for Java](https://smallrye.io/smallrye-mutiny/). |
| 11 | +
|
| 12 | +With the release of Vert.x 5, important API changes were made, sometimes breaking the compability with Vert.x 4.x projects. It was an opportunity to release a new version of the generator. This guide will walk through the changes between Vert.x-mutiny bindings 3.x and 4.x. |
| 13 | + |
| 14 | +## API changes |
| 15 | +Numerous API changes are due to the transition to Vert.x 5. |
| 16 | +The Vert.x 4 to 5 migration guide is available at https://vertx.io/docs/guides/vertx-5-migration-guide/. |
| 17 | + |
| 18 | +We provide here a brief summary of the breaking changes. |
| 19 | + |
| 20 | +### No more Callbacks |
| 21 | + |
| 22 | +Complete removal of callback methods such as: |
| 23 | + ```java |
| 24 | +void request(RequestOptions request, Handler<AsyncResult<HttpClientRequest>> callback); |
| 25 | + ``` |
| 26 | + |
| 27 | +They have all been replaced with a Future such as: |
| 28 | +```java |
| 29 | +Future<HttpClientRequest> request(RequestOptions request); |
| 30 | +``` |
| 31 | + |
| 32 | +Consequently, the bindings generator only supports the `Future` style and will generate the following: |
| 33 | +```java |
| 34 | +Uni<HttpClientRequest> request(RequestOptions request); |
| 35 | +``` |
| 36 | + |
| 37 | +### Deprecated classes are no more |
| 38 | +| Sunsetting in 4.x | Replacement in 5.x | |
| 39 | +| --------------------- | --------------------------------------------------------------------------------- | |
| 40 | +| Vert.x Sync | Vert.x virtual threads | |
| 41 | +| Service Factories | None | |
| 42 | +| Maven Service Factory | None | |
| 43 | +| HTTP Service Factory | None | |
| 44 | +| Vert.x Web OpenAPI | [Vert.x Web OpenAPI Router](https://vertx.io/docs/vertx-web-openapi-router/java/) | |
| 45 | +| *talk about CLI ?* | | |
| 46 | +### Changes with regards to @VertxGen |
| 47 | +Numerous classes are now annotated `@DataObject` instead of `@VertxGen`. `@DataObject` annotation existed in Vert.x 4.x and was used mainly for `*Options.java` classes. No wrappers are thus required, the core Vert.x interface is used directly. They will break existing projects are imports are now invalid. |
| 48 | + |
| 49 | +Below are some classes that are not "mutinified" anymore: |
| 50 | +- `io.vertx.core.buffer.Buffer` |
| 51 | +- `io.vertx.core.net.Address` |
| 52 | +- `io.vertx.core.net.SocketAddress` |
| 53 | +- `io.vertx.core.parsetools.JsonEvent` |
| 54 | +- `io.vertx.core.MultiMap` |
| 55 | +- `io.vertx.core.datagram.DatagramPacket` |
| 56 | + |
| 57 | +### SQL clients have been pruned |
| 58 | +In Vert.x 4, `Pool` subtypes were used for every kind of databases: `PgPool, MySQLPool, MSSQLPool`, etc. They have all been removed and replaced with client builder subtypes: |
| 59 | + |
| 60 | +```java |
| 61 | +// 4.x |
| 62 | +PgPool client = PgPool.pool(vertx, connectOptions, poolOptions); |
| 63 | + |
| 64 | +//5.0 |
| 65 | +Pool client = PgBuilder.pool() |
| 66 | + .with(poolOptions) |
| 67 | + .connectingTo(connectOptions) |
| 68 | + .using(vertx) |
| 69 | + .build(); |
| 70 | +``` |
| 71 | + |
| 72 | +## Dropped or replaced modules |
| 73 | + |
| 74 | +| Module | Replacement | |
| 75 | +| ------------------- | ----------------------------- | |
| 76 | +| service-discovery-* | *dropped* | |
| 77 | +| web-openapi | (openapi, web-openapi-router) | |
| 78 | +| web-auth-shiro | *dropped* | |
| 79 | +| web-auth-webauthn | web-auth-webauthn4j | |
| 80 | +| auth-jdbc | *dropped* | |
| 81 | +| jdbc-client | *dropped* | |
| 82 | +| web-api-contract | *dropped* | |
| 83 | +| web-templ-jade | *dropped* | |
| 84 | +| stomp | *dropped* | |
| 85 | +| shell | *dropped* | |
| 86 | +## Using the generator for other APIs |
| 87 | +The generator is still open source, and can still be leveraged to produce mutiny bindings for any asynchronous APIs. The generator can be used in any module. This section briefly details how to specify which classes will be subject to generation, before showing how to setup a module to enable mutiny bindings generation. |
| 88 | +### Specifying which class to bind for |
| 89 | +Let's work with a custom Java module providing a basic greeting service. |
| 90 | +```java |
| 91 | +package org.acme; |
| 92 | + |
| 93 | +import io.vertx.core.Future; |
| 94 | +import io.vertx.codegen.annotations.VertxGen; |
| 95 | + |
| 96 | +@VertxGen |
| 97 | +public interface Hello { |
| 98 | + default Future<String> hello() { |
| 99 | + return Future.succeededFuture("Hello !"); |
| 100 | + } |
| 101 | +} |
| 102 | +``` |
| 103 | + |
| 104 | +This interface returning a `Future<String>`, it is possible to generate the mutiny equivalent by annotating with `@VertxGen`. The resulting interface is below, in a new package `org.acme.mutiny`. |
| 105 | +```java |
| 106 | +package org.acme.mutiny; |
| 107 | + |
| 108 | +import io.smallrye.common.annotation.CheckReturnValue; |
| 109 | +import io.smallrye.mutiny.Uni; |
| 110 | +import io.smallrye.mutiny.vertx.MutinyDelegate; |
| 111 | +import io.smallrye.mutiny.vertx.MutinyGen; |
| 112 | +import io.smallrye.mutiny.vertx.TypeArg; |
| 113 | +import io.vertx.core.Future; |
| 114 | +import java.util.function.Supplier; |
| 115 | + |
| 116 | +/** |
| 117 | + * <strong>NOTE:</strong> This class has been automatically generated from the {@link org.acme.Hello original} non Mutiny-ified interface. |
| 118 | + * |
| 119 | + * |
| 120 | + * @see org.acme.Hello |
| 121 | + */ |
| 122 | +@MutinyGen(org.acme.Hello.class) |
| 123 | +public class Hello implements MutinyDelegate { |
| 124 | + |
| 125 | + private final org.acme.Hello delegate; |
| 126 | + |
| 127 | + /** |
| 128 | + * Create a new instance of {@link Hello} delegating to the given (non-null) instance of {@link org.acme.Hello}. |
| 129 | + */ |
| 130 | + public Hello(org.acme.Hello delegate) { |
| 131 | + // Generated by io.smallrye.mutiny.vertx.apigenerator.shims.DelegateConstructorShim |
| 132 | + this.delegate = delegate; |
| 133 | + } |
| 134 | + |
| 135 | + /** |
| 136 | + * Empty constructor used by CDI, do not use this constructor directly. |
| 137 | + */ |
| 138 | + Hello() { |
| 139 | + // Generated by io.smallrye.mutiny.vertx.apigenerator.shims.NoArgConstructorShimModule |
| 140 | + this.delegate = null; |
| 141 | + } |
| 142 | + |
| 143 | + public Hello(Object delegate) { |
| 144 | + // Generated by io.smallrye.mutiny.vertx.apigenerator.shims.DelegateAsObjectAndTypeArgsConstructorShimModule |
| 145 | + this.delegate = (org.acme.Hello) delegate; |
| 146 | + } |
| 147 | + |
| 148 | + /** |
| 149 | + * Get the <em>delegate</em> instance. |
| 150 | + * <p> |
| 151 | + * This method returns the instance on which this shim is delegating the calls. |
| 152 | + * And so, give you access to the <em>bare</em> API. |
| 153 | + * </p> |
| 154 | + * |
| 155 | + * @return the delegate instance |
| 156 | + */ |
| 157 | + public org.acme.Hello getDelegate() { |
| 158 | + return delegate; |
| 159 | + } |
| 160 | + |
| 161 | + /** |
| 162 | + * <p> |
| 163 | + * Unlike the <em>bare</em> Vert.x variant, this method returns a {@link io.smallrye.mutiny.Uni Uni}. |
| 164 | + * The uni emits the result of the operation as item. |
| 165 | + * If the operation fails, the uni emits the failure. |
| 166 | + * </p> |
| 167 | + * <p> |
| 168 | + * Don't forget to <em>subscribe</em> on it to trigger the operation. |
| 169 | + * </p> |
| 170 | + * |
| 171 | + * |
| 172 | + * |
| 173 | + * @return A {@link io.smallrye.mutiny.Uni Uni} representing the asynchronous result of this operation. |
| 174 | + * @see org.acme.Hello#hello() |
| 175 | + */ |
| 176 | + @CheckReturnValue |
| 177 | + public Uni<String> hello() { |
| 178 | + // Code generated by io.smallrye.mutiny.vertx.apigenerator.shims.UniMethodShimModule; |
| 179 | + Supplier<Future<String>> _res = () -> getDelegate().hello(); |
| 180 | + return Uni.createFrom().completionStage(() -> _res.get().toCompletionStage()); |
| 181 | + } |
| 182 | + |
| 183 | + /** |
| 184 | + * <p> |
| 185 | + * Unlike the <em>bare</em> Vert.x variant, this method returns a {@link java.lang.String}. |
| 186 | + * This method awaits <strong>indefinitely</strong> for the completion of the underlying asynchronous operation. |
| 187 | + * If the operation completes successfully, the result is returned, otherwise the failure is thrown (potentially wrapped in a {@code RuntimeException}). |
| 188 | + * </p> |
| 189 | + * |
| 190 | + * |
| 191 | + * |
| 192 | + * @return The operation result |
| 193 | + * @see org.acme.Hello#hello() |
| 194 | + */ |
| 195 | + public String helloAndAwait() { |
| 196 | + // Code generated by io.smallrye.mutiny.vertx.apigenerator.shims.UniMethodShimModule; |
| 197 | + Uni<String> _res = hello(); |
| 198 | + return _res.await().indefinitely(); |
| 199 | + } |
| 200 | + |
| 201 | + /** |
| 202 | + * <p> |
| 203 | + * Unlike the <em>bare</em> Vert.x variant, this method ignores the {@link java.lang.String} result or any failure. |
| 204 | + * </p> |
| 205 | + * |
| 206 | + * |
| 207 | + * |
| 208 | + * @return The current instance to chain operations if needed. |
| 209 | + * @see org.acme.Hello#hello() |
| 210 | + */ |
| 211 | + public Hello helloAndForget() { |
| 212 | + // Code generated by io.smallrye.mutiny.vertx.apigenerator.shims.UniMethodShimModule; |
| 213 | + hello().subscribe().with(_ignored -> {}); |
| 214 | + return this; |
| 215 | + } |
| 216 | + |
| 217 | + /** |
| 218 | + * Creates a new instance of the {@code Hello}. |
| 219 | + */ |
| 220 | + public static Hello newInstance(org.acme.Hello delegate) { |
| 221 | + // Generated by io.smallrye.mutiny.vertx.apigenerator.shims.NewInstanceMethodShimModule |
| 222 | + return delegate != null ? new Hello(delegate) : null; |
| 223 | + } |
| 224 | + |
| 225 | + @Override |
| 226 | + public int hashCode() { |
| 227 | + // // Code generated by io.smallrye.mutiny.vertx.apigenerator.shims.EqualsHashCodeAndToStringShimModule |
| 228 | + return delegate.hashCode(); |
| 229 | + } |
| 230 | + |
| 231 | + @Override |
| 232 | + public boolean equals(Object o) { |
| 233 | + // // Code generated by io.smallrye.mutiny.vertx.apigenerator.shims.EqualsHashCodeAndToStringShimModule |
| 234 | + if (this == o) return true; |
| 235 | + if (o == null || getClass() != o.getClass()) return false; |
| 236 | + Hello that = (Hello) o; |
| 237 | + return delegate.equals(that.getDelegate()); |
| 238 | + } |
| 239 | + |
| 240 | + @Override |
| 241 | + public String toString() { |
| 242 | + // // Code generated by io.smallrye.mutiny.vertx.apigenerator.shims.EqualsHashCodeAndToStringShimModule |
| 243 | + return delegate.toString(); |
| 244 | + } |
| 245 | +} |
| 246 | +``` |
| 247 | + |
| 248 | +The original interface is transformed, but the original is kept as a delegate. Other methods such as `boolean equals(Object o)`, `int hashCode()`, `String toString()`, `Hello newInstance(org.acme.Hello delegate)` are generated along with the *"mutinified"* `Uni<String> hello()` and its variants `String helloAndAwait()`, `Hello hellAndForget()`. |
| 249 | + |
| 250 | +The delegate instance is important as every call to `hello`, `helloAndAwait`, `helloAndForget` depends on the transformation of the `Future<String>` in an `Uni<String>`. |
| 251 | + |
| 252 | +> [!warning] |
| 253 | +> Every class of your module that uses an `Hello` instance or depends on the `Hello` interface should be annotated `@VertxGen` in order to use the generated `org.acme.mutiny` package instead of the original one in `org.acme`. |
| 254 | +
|
| 255 | +### Configuring a module to generate mutiny bindings |
| 256 | +It is possible to generate bindings for a module manually, by creating instances of `MutinyGenerator`, or to automate the process by adding build plugins. |
| 257 | +#### Using Maven |
| 258 | +The generator now works in three distinct phases: |
| 259 | + |
| 260 | +1. Collection |
| 261 | +2. Analyzis |
| 262 | +3. Generation |
| 263 | + |
| 264 | +Four maven build plugins are used to collect sources, analyze them, and generate new sources. |
| 265 | +- ``maven-dependency-plugin`` to gather the sources as well as potential additional sources on which we depend ; and put them is a specific directory `outputDirectory`. |
| 266 | +- ``maven-jar-plugin`` to setup the module name in the target jar. |
| 267 | +- `exec-maven-plugin` to launch the generator with the settings defined previously. This plugin depends directly on ``io.smallrye.reactive.vertx-mutiny-code-generator`` and requires the following arguments: |
| 268 | + - module name `--module-name` |
| 269 | + - source folder `--source` |
| 270 | + - additional sources folder `--additional-source` |
| 271 | + - output folder `--output` |
| 272 | + - `build-helper-maven-plugin` to tell maven that the folder in which the bindings were outputed (give as argument `--output` must be compiled and treated as sources. |
0 commit comments