Skip to content

Commit 3e11e21

Browse files
authored
Explain usage of the mapper annotation processor in the Quickstart guide (fixes #212) (#217)
1 parent e14fe5b commit 3e11e21

File tree

2 files changed

+109
-14
lines changed

2 files changed

+109
-14
lines changed

changelog/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
This release is built against Quarkus 2.15.0.Final and the Cassandra driver 4.15.0.
44

55
- [bug] [#214](https://github.com/datastax/cassandra-quarkus/issues/214) DAO initialization is not happening on main thread with eager init
6+
- [documentation] [#212](https://github.com/datastax/cassandra-quarkus/issues/212) Explain usage of the mapper annotation processor in the Quickstart guide
67

78
### 1.1.2
89

quickstart/README.adoc

Lines changed: 108 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public class Fruit {
9595

9696
As stated above, we are using the DataStax Object Mapper. In other words, we are not going to write
9797
our CQL queries manually; instead, we will annotate our data model with a few annotations, and the
98-
mapper will generate proper CQL queries underneath.
98+
mapper will generate proper CQL queries for us underneath.
9999

100100
This is why the `Fruit` class is annotated with `@Entity`: this annotation marks it as an _entity
101101
class_ that is mapped to a Cassandra table. Its instances are meant to be automatically persisted
@@ -131,7 +131,7 @@ Note also the special return type of the `findAll` method,
131131
link:https://docs.datastax.com/en/drivers/java/latest/com/datastax/oss/driver/api/core/PagingIterable.html[`PagingIterable`]:
132132
it's the base type of result sets returned by the driver.
133133

134-
Finally, let's create the a Mapper interface:
134+
Finally, let's create a Mapper interface:
135135

136136
[source,java]
137137
----
@@ -146,6 +146,96 @@ The `@Mapper` annotation is yet another annotation recognized by the DataStax Ob
146146
mapper is responsible for constructing instances of DAOs – in this case, out mapper is constructing
147147
an instance of our only DAO, `FruitDao`.
148148

149+
Think of the mapper interface as a factory for DAO beans: if you intend to construct and inject a
150+
specific DAO bean in your own code, then you first need to add a `@DaoFactory` method for it in a
151+
`@Mapper` interface.
152+
153+
TIP: `@DaoFactory` method names are irrelevant.
154+
155+
`@DaoFactory` methods should return beans of the following types:
156+
157+
- Any `@Dao`-annotated interface, e.g. `FruitDao`;
158+
- A `CompletationStage` of any `@Dao`-annotated interface, e.g. `CompletionStage<FruitDao>`.
159+
- A `Uni` of any `@Dao`-annotated interface, e.g. `Uni<FruitDao>`.
160+
161+
TIP: `Uni` is a type from the Mutiny library, which is the reactive programming library used by
162+
Quarkus. This will be explained in more detail in the "Reactive Programming" section below.
163+
164+
== Generating the DAO and Mapper Implementations
165+
166+
As you probably guessed already, we are not going to implement the interfaces above. Instead, the
167+
Object Mapper will generate such implementations for us.
168+
169+
The Object Mapper is composed of 2 pieces:
170+
171+
1. A (compile-time) annotation processor that scans the classpath for classes annotated with
172+
`@Entity`, and generates code for them; and
173+
2. A runtime module that contains the logic to execute the generated queries.
174+
175+
Therefore, enabling the Object Mapper requires two steps:
176+
177+
1. Declare the `cassandra-quarkus-mapper-processor` annotation processor. With Maven, this is done
178+
by modifying the compiler plugin configuration in the project's `pom.xml` file as follows:
179+
180+
[source,xml]
181+
----
182+
<plugin>
183+
<artifactId>maven-compiler-plugin</artifactId>
184+
<version>3.10.1</version>
185+
<configuration>
186+
<source>${java.version}</source>
187+
<target>${java.version}</target>
188+
<annotationProcessorPaths>
189+
<path>
190+
<groupId>com.datastax.oss.quarkus</groupId>
191+
<artifactId>cassandra-quarkus-mapper-processor</artifactId>
192+
<version>${cassandra-quarkus.version}</version>
193+
</path>
194+
</annotationProcessorPaths>
195+
</configuration>
196+
</plugin>
197+
----
198+
199+
With Gradle, this is done by adding the following line to the `build.gradle` file:
200+
201+
[source,groovy]
202+
----
203+
annotationProcessor "com.datastax.oss.quarkus:cassandra-quarkus-mapper-processor:${cassandra-quarkus.version}"
204+
----
205+
206+
IMPORTANT: make sure you are enabling the right annotation processor! The Cassandra Quarkus
207+
extension requires the `cassandra-quarkus-mapper-processor` annotation processor, and not the Java
208+
driver's `java-driver-mapper-processor`. The former has more capabilities than the latter, and is
209+
the only one suitable for use in a Quarkus application.
210+
211+
[start=2]
212+
1. Declare the `cassandra-quarkus-mapper-runtime` dependency in compile scope in the project's
213+
`pom.xml` file as follows:
214+
215+
[source,xml]
216+
----
217+
<dependency>
218+
<groupId>com.datastax.oss.quarkus</groupId>
219+
<artifactId>cassandra-quarkus-mapper-runtime</artifactId>
220+
<version>${project.version}</version>
221+
<scope>compile</scope>
222+
</dependency>
223+
----
224+
225+
With Gradle, this is done by adding the following line to the `build.gradle` file:
226+
227+
[source,groovy]
228+
----
229+
compile "com.datastax.oss.quarkus:cassandra-quarkus-mapper-runtime:${cassandra-quarkus.version}"
230+
----
231+
232+
IMPORTANT: Although this module is called "runtime", it must be declared in compile scope.
233+
234+
If your project is correctly set up, you should now be able to compile it without errors, and you
235+
should see the generated code in the `target/generated-sources/annotations` directory (if you are
236+
using Maven). You don't need to get familiar with the generated code though, as it is mostly
237+
internal machinery to interact with the database.
238+
149239
== Creating a Service & JSON REST Endpoint
150240

151241
Now let's create a `FruitService` that will be the business layer of our application and store/load
@@ -169,19 +259,20 @@ public class FruitService {
169259
----
170260

171261
Note how the service is being injected a `FruitDao` instance. This DAO instance is injected
172-
automatically.
262+
automatically, thanks to the generated implementations.
173263

174264
The Cassandra Quarkus extension allows you to inject any of the following beans in your own
175265
components:
176266

177267
- All `@Mapper`-annotated interfaces in your project.
178-
- All `@Dao`-annotated interfaces in your project, as long as they are produced by a corresponding
179-
`@DaoFactory`-annotated method declared in a mapper interface from your project.
268+
- You can also inject a `CompletionStage` or `Uni` of any `@Mapper`-annotated interface.
269+
- Any bean returned by a `@DaoFactory` method (see above for possible bean types).
180270
- The
181271
link:https://javadoc.io/doc/com.datastax.oss.quarkus/cassandra-quarkus-client/latest/com/datastax/oss/quarkus/runtime/api/session/QuarkusCqlSession.html[`QuarkusCqlSession`]
182272
bean: this application-scoped, singleton bean is your main entry point to the Cassandra client; it
183273
is a specialized Cassandra driver session instance with a few methods tailored especially for
184274
Quarkus. Read its javadocs carefully!
275+
- You can also inject `CompletationStage<QuarkusCqlSession>` or `Uni<QuarkusCqlSession>`.
185276

186277
In our example, both `FruitMapper` and `FruitDao` could be injected anywhere. We chose to inject
187278
`FruitDao` in `FruitService`.
@@ -375,7 +466,8 @@ docker exec -it local-cassandra-instance cqlsh
375466

376467
In the project root directory:
377468

378-
- Run `mvn clean package` and then `java -jar ./target/cassandra-quarkus-quickstart-*-runner.jar` to start the application;
469+
- Run `mvn clean package` and then `java -jar ./target/cassandra-quarkus-quickstart-*-runner.jar` to
470+
start the application;
379471
- Or better yet, run the application in dev mode: `mvn clean quarkus:dev`.
380472

381473
Now you can use curl commands to interact with the underlying REST API.
@@ -424,7 +516,7 @@ link:https://quarkus.io/guides/getting-started-reactive[Getting Started with Rea
424516

425517
Let's rewrite our application using reactive programming with Mutiny.
426518

427-
First, let's to declare another DAO interface that works in a reactive way:
519+
First, let's declare another DAO interface that works in a reactive way:
428520

429521
[source,java]
430522
----
@@ -771,15 +863,17 @@ You can then point your browser to `http://localhost:8080/fruits.html` and use y
771863

772864
== Eager vs Lazy Initialization
773865

774-
This extension allows you to inject either:
866+
As explained above, this extension allows you to inject many types of beans:
775867

776-
- a `QuarkusCqlSession` bean;
777-
- or the asynchronous version of this bean, that is, `CompletionStage<QuarkusCqlSession>`;
778-
- or the reactive version of this bean, that is, `Uni<QuarkusCqlSession>`.
868+
- A simple bean like `QuarkusCqlSession` or `FruitDao`;
869+
- The asynchronous version of that bean, e.g. `CompletionStage<QuarkusCqlSession>` or
870+
`CompletionStage<FruitDao>;
871+
- The reactive version of that bean, e.g., `Uni<QuarkusCqlSession>` or `Uni<FruitDao>`.
779872

780-
The most straightforward approach is obviously to inject `QuarkusCqlSession` directly. This should
781-
work just fine for most applications; however, the `QuarkusCqlSession` bean needs to be initialized
782-
before it can be used, and this process is blocking.
873+
The most straightforward approach is obviously to inject the bean directly. This should work just
874+
fine for most applications; however, the `QuarkusCqlSession` bean, and all DAO beans that depend on
875+
it, might take some time to initialize before they can be used for the first time, and this process
876+
is blocking.
783877

784878
Fortunately, it is possible to control when the initialization should happen: the
785879
`quarkus.cassandra.init.eager-init` parameter determines if the `QuarkusCqlSession` bean should be

0 commit comments

Comments
 (0)