Skip to content

Commit

Permalink
walkthrough documentation - core api dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
JohT committed Dec 20, 2021
1 parent 6d0197b commit 7632f12
Showing 1 changed file with 52 additions and 0 deletions.
52 changes: 52 additions & 0 deletions showcase-quarkus-eventsourcing/WALKTHROUGH.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ The following topics are meant to lead you through the code and highlight most i
* [Connecting CDI to AxonFramework](#Connecting-CDI-to-AxonFramework)
* [Connecting JTA Transactions to AxonFramework](#Connecting-JTA-Transactions-to-AxonFramework)
* [Connecting JSON Binding to AxonFramework](#Connecting-JSON-Binding-to-AxonFramework)
* [Core API without dependencies](#Core-API-without-dependencies)

## Connecting CDI to AxonFramework

Expand Down Expand Up @@ -55,12 +56,61 @@ This is pretty similar to [AxonFramework/cdi JtaTransactionManager.java](https:/
AxonFramework has build-in support for Jackson JSON serializer. Some of its internal serializable data types need to be adapted to be used with [JSON Binding][JSONBinding].
The ones needed here are internally registered in [JsonbAxonAdapterRegister.java](./src/main/java/io/github/joht/showcase/quarkuseventsourcing/messaging/infrastructure/axon/serializer/jsonb/axon/adapter/JsonbAxonAdapterRegister.java). Except for the generic [JsonbMetaDataAdapter.java](./src/main/java/io/github/joht/showcase/quarkuseventsourcing/messaging/infrastructure/axon/serializer/jsonb/axon/adapter/JsonbMetaDataAdapter.java) and [JsonbReplayTokenAdapter.java](./src/main/java/io/github/joht/showcase/quarkuseventsourcing/messaging/infrastructure/axon/serializer/jsonb/axon/adapter/JsonbReplayTokenAdapter.java) they shouldn't be needed any more since [AxonFramework PullRequest #1163](https://github.com/AxonFramework/AxonFramework/pull/1163).

## Mitigate Core API dependencies

The core API contains value objects of all messages (events, commands, queries). These can be found in the package [message](./src/main/java/io/github/joht/showcase/quarkuseventsourcing/message).

As a reference [AxonFramework Giftcard Example][AxonFrameworkGiftcardExample] shows how these could be defined using Kotlin (see "coreapi" package").

The core API might become a separate module and will be shared upon command- and query-side implementations. Shared libraries (e.g. APIs) need to be treated with special care. Changes might introduce changes in dependent modules (coupling). They may also introduce version conflicts, if the dependent module needs a library in a different version. To mitigate that, the shared API should ideally be self contained and only depend on java itself.

**ℹ** Currently (2021) there is a dependency to the bean validation API. This could also be replaced.

### Command message types without axon dependency

Command messages need a property that matches the id of the aggregate they belong to.
Since they may also contain other properties, the property with the aggregate identifier needs to be annotated. There is a way to get this done without depending on axon (in the API):
* Provide a own annotation (that itself depends only on java) within the API like
[CommandTargetAggregateIdentifier.java](./src/main/java/io/github/joht/showcase/quarkuseventsourcing/message/command/CommandTargetAggregateIdentifier.java)
* Annotate the command type with the co-located annotation like in [ChangeNicknameCommand.java](./src/main/java/io/github/joht/showcase/quarkuseventsourcing/message/command/account/ChangeNicknameCommand.java)
* Configure AxonFramework to use the custom annotation like in [AxonAggregateConfiguration.java](./src/main/java/io/github/joht/showcase/quarkuseventsourcing/messaging/infrastructure/axon/AxonAggregateConfiguration.java)

The following code shows the essential part of the configuration:

```java
AnnotationCommandTargetResolver.builder()
.targetAggregateIdentifierAnnotation(CommandTargetAggregateIdentifier.class)
.targetAggregateVersionAnnotation(CommandTargetAggregateVersion.class).build();
```

### Message Value Objects without JSON library dependencies

Plain old java objects (POJO) are widely supported by almost any serialization (JSON, XML,..) library.
When Domain Driven Design is applied, value objects should be immutable.
Their properties should only be set once during creation and should then remain unchangeable.
This is usually done by using constructor parameters. To simplify creating complex objects, builders can be provided as well.

When it comes to immutable value objects using constructor parameters, serialization libraries need to know which field should be mapped to which constructor argument in the right order. If there are a couple of constructors, it gets even more complicated.

Therefore, serialization libraries provide annotations for constructors. This introduces additional dependencies. These can be avoided by using the build-in [java.beans.ConstructorProperties Annotation][ConstructorProperties], that is now widely supported (Jackson, Yasson, ...).

As an example have a look at [ChangeNicknameCommand.java](./src/main/java/io/github/joht/showcase/quarkuseventsourcing/message/command/account/ChangeNicknameCommand.java).

#### Further ideas:

Of course this is only one way to do it. Some other ideas i'vent tried yet:
* Kotlin directly supports immutable types with data classes. It would be interesting to see, how serialization integrates with them.
* Java 14 introduces records. Serialization integration would also be interesting here.
* Using Open API ("swagger") to declare message types and generate the API at build time.

## References

* [Axon Framework CDI Support][AxonFrameworkCDI]
* [AxonFramework Giftcard Example][AxonFrameworkGiftcardExample]
* [AxonFramework Parameter Resolver][AxonFrameworkParameterResolver]
* [Building a native executable][QuarkusNativeExecutable]
* [CDI Portable Extension][CDIExtension]
* [java.beans.ConstructorProperties Annotation][ConstructorProperties]
* [Eclipse MicroProfile][MicroProfile]
* [Flyway Version control for your database][Flyway]
* [Jakarta JSON Binding][JSONBinding]
Expand All @@ -71,7 +121,9 @@ The ones needed here are internally registered in [JsonbAxonAdapterRegister.java

[AxonFrameworkCDI]: https://github.com/AxonFramework/extension-cdi
[AxonFrameworkParameterResolver]: https://axoniq.io/blog-overview/parameter-resolvers-axon
[AxonFrameworkGiftcardExample]: https://github.com/AxonFramework/extension-springcloud-sample
[CDIExtension]: https://docs.jboss.org/weld/reference/latest/en-US/html/extend.html
[ConstructorProperties]: https://docs.oracle.com/javase/8/docs/api/java/beans/ConstructorProperties.html
[Flyway]: https://flywaydb.org
[JakartaTransaction]: https://jakarta.ee/specifications/transactions/
[JSONBinding]: https://jakarta.ee/specifications/jsonb/2.0/jakarta-jsonb-spec-2.0.html
Expand Down

0 comments on commit 7632f12

Please sign in to comment.