From feda4d11bb774d927f3a1b4e430698f3148c5a17 Mon Sep 17 00:00:00 2001 From: Jan Galinski Date: Sat, 7 Sep 2024 10:58:19 +0200 Subject: [PATCH 1/2] chore: graceful shutdown --- .../main/kotlin/AxonAvroExampleApplication.kt | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/_examples/axon-avro-holi-bank-example/src/main/kotlin/AxonAvroExampleApplication.kt b/_examples/axon-avro-holi-bank-example/src/main/kotlin/AxonAvroExampleApplication.kt index 69199ce..376496e 100644 --- a/_examples/axon-avro-holi-bank-example/src/main/kotlin/AxonAvroExampleApplication.kt +++ b/_examples/axon-avro-holi-bank-example/src/main/kotlin/AxonAvroExampleApplication.kt @@ -12,9 +12,12 @@ import org.axonframework.queryhandling.QueryGateway import org.axonframework.serialization.Serializer import org.axonframework.serialization.json.JacksonSerializer import org.springframework.beans.factory.annotation.Qualifier +import org.springframework.boot.SpringApplication import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.context.event.ApplicationStartedEvent import org.springframework.boot.runApplication +import org.springframework.context.ApplicationContext +import org.springframework.context.ApplicationContextAware import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.context.annotation.Primary @@ -55,10 +58,12 @@ class AxonAvroExampleApplication { class ExampleRunner( val commandGateway: CommandGateway, val queryGateway: QueryGateway - ) { + ) : ApplicationContextAware { companion object : KLogging() + private lateinit var applicationContext: ApplicationContext + @EventListener fun runExample(event: ApplicationStartedEvent) { logger.info { @@ -124,7 +129,7 @@ class AxonAvroExampleApplication { Transactions for account $bankAccountId: -${transactions.items.joinToString( separator = "\n")} +${transactions.items.joinToString(separator = "\n")} ================================================================================ """.trimIndent() @@ -138,6 +143,13 @@ ${transactions.items.joinToString( separator = "\n")} =============================================================================== """.trimIndent() } + + SpringApplication.exit(applicationContext, { 0 }) } + + override fun setApplicationContext(applicationContext: ApplicationContext) { + this.applicationContext = applicationContext + } + } } From e6cf8da84757217ebc44e636541e701e9c17cdf0 Mon Sep 17 00:00:00 2001 From: Jan Galinski Date: Sun, 8 Sep 2024 00:16:36 +0200 Subject: [PATCH 2/2] introduce jmolecules --- _examples/axon-avro-holi-bank-example/pom.xml | 26 +- axon-avro-generation/pom.xml | 31 ++ .../src/main/kotlin/AxonAvroGeneration.kt | 19 +- .../main/kotlin/meta/RecordMetaDataType.kt | 1 + .../AxonRevisionAnnotationProcessor.kt | 2 +- ...AxonTargetIdentifierAnnotationProcessor.kt | 15 +- ...JMoleculesAnnotationRecordTypeProcessor.kt | 43 +++ ...tations.kt => AxonFrameworkAnnotations.kt} | 20 +- .../support/JMoleculesAnnotationSupplier.kt | 294 ++++++++++++++++++ ...lin.generation.spi.KotlinCodeGenerationSpi | 2 + 10 files changed, 436 insertions(+), 17 deletions(-) create mode 100644 axon-avro-generation/src/main/kotlin/processor/JMoleculesAnnotationRecordTypeProcessor.kt rename axon-avro-generation/src/main/kotlin/support/{_annotations.kt => AxonFrameworkAnnotations.kt} (56%) create mode 100644 axon-avro-generation/src/main/kotlin/support/JMoleculesAnnotationSupplier.kt diff --git a/_examples/axon-avro-holi-bank-example/pom.xml b/_examples/axon-avro-holi-bank-example/pom.xml index 8acd453..d05fb07 100644 --- a/_examples/axon-avro-holi-bank-example/pom.xml +++ b/_examples/axon-avro-holi-bank-example/pom.xml @@ -27,6 +27,13 @@ import pom + + org.jmolecules + jmolecules-bom + 2023.1.2 + import + pom + @@ -73,6 +80,21 @@ jakarta.annotation-api + + org.jmolecules + kmolecules-ddd + + + + org.jmolecules + jmolecules-cqrs-architecture + + + + org.jmolecules + jmolecules-events + + org.mockito.kotlin @@ -110,7 +132,9 @@ io.toolisticon.kotlin.avro.maven avro-kotlin-maven-plugin ${avro-kotlin.version} - + + NONE + generate-schema diff --git a/axon-avro-generation/pom.xml b/axon-avro-generation/pom.xml index b1eb955..3acd112 100644 --- a/axon-avro-generation/pom.xml +++ b/axon-avro-generation/pom.xml @@ -15,6 +15,18 @@ ${project.artifactId} Axon Avro Generation - strategies and processors for avro-kotlin-generator. + + + + org.jmolecules + jmolecules-bom + 2023.1.2 + import + pom + + + + io.toolisticon.kotlin.avro @@ -45,6 +57,25 @@ kotlin-code-generation-test test + + + + org.jmolecules + kmolecules-ddd + test + + + + org.jmolecules + jmolecules-cqrs-architecture + test + + + + org.jmolecules + jmolecules-events + test + diff --git a/axon-avro-generation/src/main/kotlin/AxonAvroGeneration.kt b/axon-avro-generation/src/main/kotlin/AxonAvroGeneration.kt index 383509a..cb3002d 100644 --- a/axon-avro-generation/src/main/kotlin/AxonAvroGeneration.kt +++ b/axon-avro-generation/src/main/kotlin/AxonAvroGeneration.kt @@ -2,5 +2,22 @@ package io.holixon.axon.avro.generation object AxonAvroGeneration { - // empty marker + + object jmolecules { + + val ddd = try { + Class.forName("org.jmolecules.ddd.annotation.AggregateRoot") + true + } catch (e: ClassNotFoundException) { + false + } + + val cqrs = try { + Class.forName("org.jmolecules.ddd.annotation.AggregateRoot") + true + } catch (e: ClassNotFoundException) { + false + } + } + } diff --git a/axon-avro-generation/src/main/kotlin/meta/RecordMetaDataType.kt b/axon-avro-generation/src/main/kotlin/meta/RecordMetaDataType.kt index decfc7f..d6d65ab 100644 --- a/axon-avro-generation/src/main/kotlin/meta/RecordMetaDataType.kt +++ b/axon-avro-generation/src/main/kotlin/meta/RecordMetaDataType.kt @@ -11,6 +11,7 @@ enum class RecordMetaDataType { Command, Query, QueryResult, + Undefined, ; val decapitalizedName = name.replaceFirstChar { c -> c.lowercase(Locale.getDefault()) } diff --git a/axon-avro-generation/src/main/kotlin/processor/AxonRevisionAnnotationProcessor.kt b/axon-avro-generation/src/main/kotlin/processor/AxonRevisionAnnotationProcessor.kt index f76b2ab..7240f0a 100644 --- a/axon-avro-generation/src/main/kotlin/processor/AxonRevisionAnnotationProcessor.kt +++ b/axon-avro-generation/src/main/kotlin/processor/AxonRevisionAnnotationProcessor.kt @@ -2,7 +2,7 @@ package io.holixon.axon.avro.generation.processor import com.squareup.kotlinpoet.ExperimentalKotlinPoetApi import io.holixon.axon.avro.generation.meta.RecordMetaData.Companion.recordMetaData -import io.holixon.axon.avro.generation.support.RevisionAnnotation +import io.holixon.axon.avro.generation.support.AxonFrameworkAnnotations.RevisionAnnotation import io.toolisticon.kotlin.avro.generator.processor.KotlinDataClassFromRecordTypeProcessorBase import io.toolisticon.kotlin.avro.generator.spi.SchemaDeclarationContext import io.toolisticon.kotlin.avro.model.RecordType diff --git a/axon-avro-generation/src/main/kotlin/processor/AxonTargetIdentifierAnnotationProcessor.kt b/axon-avro-generation/src/main/kotlin/processor/AxonTargetIdentifierAnnotationProcessor.kt index f926f69..6bee4ea 100644 --- a/axon-avro-generation/src/main/kotlin/processor/AxonTargetIdentifierAnnotationProcessor.kt +++ b/axon-avro-generation/src/main/kotlin/processor/AxonTargetIdentifierAnnotationProcessor.kt @@ -3,7 +3,8 @@ package io.holixon.axon.avro.generation.processor import com.squareup.kotlinpoet.ExperimentalKotlinPoetApi import io.holixon.axon.avro.generation.meta.FieldMetaData.Companion.fieldMetaData import io.holixon.axon.avro.generation.meta.FieldMetaDataType -import io.holixon.axon.avro.generation.support.TargetAggregateIdentifierAnnotation +import io.holixon.axon.avro.generation.support.AxonFrameworkAnnotations.TargetAggregateIdentifierAnnotation +import io.holixon.axon.avro.generation.support.JMoleculesAnnotationSupplier.AssociationAnnotation import io.toolisticon.kotlin.avro.generator.processor.ConstructorPropertyFromRecordFieldProcessorBase import io.toolisticon.kotlin.avro.generator.spi.SchemaDeclarationContext import io.toolisticon.kotlin.avro.model.RecordField @@ -13,14 +14,18 @@ import io.toolisticon.kotlin.generation.builder.KotlinConstructorPropertySpecBui @OptIn(ExperimentalKotlinPoetApi::class) class AxonTargetIdentifierAnnotationProcessor : ConstructorPropertyFromRecordFieldProcessorBase() { - override fun invoke(context: SchemaDeclarationContext, input: RecordField, builder: KotlinConstructorPropertySpecBuilder): KotlinConstructorPropertySpecBuilder = builder.apply { - requireNotNull(input) + override fun invoke( + context: SchemaDeclarationContext, + input: RecordField, + builder: KotlinConstructorPropertySpecBuilder + ): KotlinConstructorPropertySpecBuilder = builder.apply { + + AssociationAnnotation().addIfEnabled(this) + addAnnotation(TargetAggregateIdentifierAnnotation) } override fun test(ctx: SchemaDeclarationContext, input: Any): Boolean { return super.test(ctx, input) && input is RecordField && input.fieldMetaData()?.type == FieldMetaDataType.Association } - - } diff --git a/axon-avro-generation/src/main/kotlin/processor/JMoleculesAnnotationRecordTypeProcessor.kt b/axon-avro-generation/src/main/kotlin/processor/JMoleculesAnnotationRecordTypeProcessor.kt new file mode 100644 index 0000000..e5ed2a4 --- /dev/null +++ b/axon-avro-generation/src/main/kotlin/processor/JMoleculesAnnotationRecordTypeProcessor.kt @@ -0,0 +1,43 @@ +package io.holixon.axon.avro.generation.processor + +import com.squareup.kotlinpoet.ExperimentalKotlinPoetApi +import io.holixon.axon.avro.generation.meta.RecordMetaData.Companion.recordMetaData +import io.holixon.axon.avro.generation.meta.RecordMetaDataType +import io.holixon.axon.avro.generation.meta.RecordMetaDataType.Command +import io.holixon.axon.avro.generation.meta.RecordMetaDataType.Event +import io.holixon.axon.avro.generation.meta.RecordMetaDataType.Query +import io.holixon.axon.avro.generation.meta.RecordMetaDataType.QueryResult +import io.holixon.axon.avro.generation.meta.RecordMetaDataType.Undefined +import io.holixon.axon.avro.generation.support.JMoleculesAnnotationSupplier.CommandAnnotation +import io.holixon.axon.avro.generation.support.JMoleculesAnnotationSupplier.DomainEventAnnotation +import io.toolisticon.kotlin.avro.generator.processor.KotlinDataClassFromRecordTypeProcessorBase +import io.toolisticon.kotlin.avro.generator.spi.SchemaDeclarationContext +import io.toolisticon.kotlin.avro.model.RecordType +import io.toolisticon.kotlin.generation.builder.KotlinDataClassSpecBuilder + +@OptIn(ExperimentalKotlinPoetApi::class) +class JMoleculesAnnotationRecordTypeProcessor : KotlinDataClassFromRecordTypeProcessorBase() { + + private fun recordMetaDataType(input: Any): RecordMetaDataType = if (input is RecordType) { + input.recordMetaData()?.type ?: Undefined + } else { + Undefined + } + + override fun invoke( + context: SchemaDeclarationContext, + input: RecordType, + builder: KotlinDataClassSpecBuilder + ): KotlinDataClassSpecBuilder = builder.apply { + when (recordMetaDataType(input)) { + Event -> DomainEventAnnotation(input.canonicalName).addIfEnabled(this) + Command -> CommandAnnotation(input.canonicalName).addIfEnabled(this) + Query, QueryResult, Undefined -> { + } + } + } + + override fun test(ctx: SchemaDeclarationContext, input: Any): Boolean { + return super.test(ctx, input) && Undefined != recordMetaDataType(input) + } +} diff --git a/axon-avro-generation/src/main/kotlin/support/_annotations.kt b/axon-avro-generation/src/main/kotlin/support/AxonFrameworkAnnotations.kt similarity index 56% rename from axon-avro-generation/src/main/kotlin/support/_annotations.kt rename to axon-avro-generation/src/main/kotlin/support/AxonFrameworkAnnotations.kt index 2633cb3..bad6414 100644 --- a/axon-avro-generation/src/main/kotlin/support/_annotations.kt +++ b/axon-avro-generation/src/main/kotlin/support/AxonFrameworkAnnotations.kt @@ -9,15 +9,17 @@ import org.axonframework.modelling.command.TargetAggregateIdentifier import org.axonframework.serialization.Revision @OptIn(ExperimentalKotlinPoetApi::class) -data class RevisionAnnotation( - val value: String, -) : KotlinAnnotationSpecSupplier { - override fun spec(): KotlinAnnotationSpec = buildAnnotation(Revision::class) { - addMember(FORMAT_STRING, value) +object AxonFrameworkAnnotations { + + data class RevisionAnnotation( + val value: String, + ) : KotlinAnnotationSpecSupplier { + override fun spec(): KotlinAnnotationSpec = buildAnnotation(Revision::class) { + addMember(FORMAT_STRING, value) + } } -} -@OptIn(ExperimentalKotlinPoetApi::class) -data object TargetAggregateIdentifierAnnotation : KotlinAnnotationSpecSupplier { - override fun spec(): KotlinAnnotationSpec = buildAnnotation(TargetAggregateIdentifier::class) + data object TargetAggregateIdentifierAnnotation : KotlinAnnotationSpecSupplier { + override fun spec(): KotlinAnnotationSpec = buildAnnotation(TargetAggregateIdentifier::class) + } } diff --git a/axon-avro-generation/src/main/kotlin/support/JMoleculesAnnotationSupplier.kt b/axon-avro-generation/src/main/kotlin/support/JMoleculesAnnotationSupplier.kt new file mode 100644 index 0000000..13e3c77 --- /dev/null +++ b/axon-avro-generation/src/main/kotlin/support/JMoleculesAnnotationSupplier.kt @@ -0,0 +1,294 @@ +package io.holixon.axon.avro.generation.support + +import com.squareup.kotlinpoet.ExperimentalKotlinPoetApi +import io.holixon.axon.avro.generation.support.JMoleculesAnnotationSupplier.JMoleculesFeature.* +import io.toolisticon.kotlin.avro.value.CanonicalName +import io.toolisticon.kotlin.avro.value.CanonicalName.Companion.parse +import io.toolisticon.kotlin.generation.KotlinCodeGeneration.buildAnnotation +import io.toolisticon.kotlin.generation.KotlinCodeGeneration.className +import io.toolisticon.kotlin.generation.builder.KotlinAnnotatableBuilder +import io.toolisticon.kotlin.generation.spec.KotlinAnnotationSpec +import io.toolisticon.kotlin.generation.spec.KotlinAnnotationSpecSupplier +import kotlin.reflect.KClass + +@OptIn(ExperimentalKotlinPoetApi::class) +sealed interface JMoleculesAnnotationSupplier : KotlinAnnotationSpecSupplier { + val feature: JMoleculesFeature + + enum class JMoleculesFeature(val markerClass: CanonicalName) { + + DDD(parse("org.jmolecules.ddd.annotation.AggregateRoot")), + CQRS(parse("org.jmolecules.architecture.cqrs.Command")), + EVENTS(parse("org.jmolecules.event.annotation.DomainEvent")), + ; + + val enabled: Boolean = try { + Class.forName(markerClass.fqn) + true + } catch (e: ClassNotFoundException) { + false + } + + fun className(type: String) = className(markerClass.namespace.value, type) + } + + + enum class PublisherType { + + /** + * Expresses that the events published are intended for internal usage. + */ + INTERNAL, + + /** + * Expresses that the events published are intended for external usage. + */ + EXTERNAL, + + /** + * Expresses that the target audience of the events is undefined (default). + */ + UNDEFINED; + } + + + fun addIfEnabled(builder: KotlinAnnotatableBuilder<*>) = if (feature.enabled) { + val annotation = spec() + builder.addAnnotation(annotation) + } else { + builder + } + + fun className(type: String) = feature.className(type) + + /** + * A domain event is a full-fledged part of the domain model, a representation of something that happened in the domain. + * + * Retention: RUNTIME + * Target: Type + */ + data class DomainEventAnnotation( + private val eventName: CanonicalName, + ) : JMoleculesAnnotationSupplier { + + override val feature: JMoleculesFeature = EVENTS + + override fun spec(): KotlinAnnotationSpec = buildAnnotation(className("DomainEvent")) { + addStringMember("namespace", eventName.namespace.value) + addStringMember("name", eventName.name.value) + } + } + + /** + * Identifies a command in the context of CQRS, i.e. a request to the system for the change of data. + * + * Retention: RUNTIME + * Target: TYPE + */ + data class CommandAnnotation( + private val commandName: CanonicalName, + ) : JMoleculesAnnotationSupplier { + override val feature = CQRS + override fun spec(): KotlinAnnotationSpec = buildAnnotation(className("Command")) { + addStringMember("namespace", commandName.namespace.value) + addStringMember("name", commandName.name.value) + } + } + + /** + * Identifies a domain event handler, i.e. logic to process a {@link DomainEvent}. + * + * Retention: RUNTIME + * Target: METHOD, ANNOTATION_TYPE + */ + data class DomainEventHandlerAnnotation( + private val eventName: CanonicalName, + ) : JMoleculesAnnotationSupplier { + + override val feature = EVENTS + + override fun spec(): KotlinAnnotationSpec = buildAnnotation(className("DomainEventHandler")) { + addStringMember("namespace", eventName.namespace.value) + addStringMember("name", eventName.name.value) + } + } + + /** + * Identifies a domain event publisher, i.e. logic to publish a {@link DomainEvent}. + * + * Retention: RUNTIME + * Target: METHOD, ANNOTATION_TYPE + */ + data class DomainEventPublisherAnnotation( + private val eventName: CanonicalName, + private val publisher: PublisherType = PublisherType.UNDEFINED, + ) : JMoleculesAnnotationSupplier { + override val feature = EVENTS + + override fun spec(): KotlinAnnotationSpec = buildAnnotation(className("DomainEventPublisher")) { + addStringMember("publishes", eventName.fqn) + addEnumMember("type", publisher) + } + } + + /** + * Annotation to marks domain events as to be externalized, which means that they are intended to be published to + * infrastructure outside the application. + * + * Retention: RUNTIME + * Target: TYPE + */ + data class ExternalizedAnnotation( + private val target: String, + ) : JMoleculesAnnotationSupplier { + + override val feature = EVENTS + + override fun spec(): KotlinAnnotationSpec = buildAnnotation(className("Externalized")) { + addStringMember("target", target) + } + } + + /** + * Identifies a command dispatcher in the context of CQRS, i.e. logic to dispatch a {@link Command}. + * + * Retention: RUNTIME + * Target: METHOD, ANNOTATION_TYPE + */ + data class CommandDispatcherAnnotation( + private val commandName: CanonicalName, + ) : JMoleculesAnnotationSupplier { + + override val feature = CQRS + + override fun spec(): KotlinAnnotationSpec = buildAnnotation(feature.className("CommandDispatcher")) { + /** + * Optional identification of the command dispatched by this dispatcher. + */ + addStringMember("dispatches", commandName.fqn) + } + } + + /** + * Identifies a command handler in the context of CQRS, i.e. logic to process a {@link Command}. + * + * Retention: RUNTIME + * Target: METHOD, ANNOTATION_TYPE, CONSTRUCTOR + */ + data class CommandHandlerAnnotation( + private val commandName: CanonicalName, + ) : JMoleculesAnnotationSupplier { + override val feature = CQRS + override fun spec(): KotlinAnnotationSpec = buildAnnotation(className("CommandHandler")) { + addStringMember("namespace", commandName.namespace.value) + addStringMember("name", commandName.name.value) + } + } + + /** + * Identifies a query model element in the context of CQRS. + * + * Retention: RUNTIME + * @Target(ElementType.TYPE) + */ + data object QueryModelAnnotation : JMoleculesAnnotationSupplier { + override val feature = CQRS + override fun spec(): KotlinAnnotationSpec = buildAnnotation(className("QueryModel")) + } + + /** + * Identifies an aggregate root, i.e. the root entity of an aggregate. + * + * Retention: RUNTIME + * Target: CLASS + */ + data object AggregateRootAnnotation : JMoleculesAnnotationSupplier { + override val feature = DDD + override fun spec(): KotlinAnnotationSpec = buildAnnotation(className("AggregateRoot")) + } + + /** + * An association to an [org.jmolecules.ddd.annotation.AggregateRoot]. + * + * Retention: RUNTIME + * Target: ANNOTATION_CLASS, FIELD, PROPERTY, PROPERTY_GETTER + */ + data class AssociationAnnotation( + private val aggregateType: KClass<*>? = null, + ) : JMoleculesAnnotationSupplier { + override val feature = DDD + override fun spec(): KotlinAnnotationSpec = buildAnnotation(className("Association")) { + aggregateType?.let { + this.addKClassMember("aggregateType", it) + } + } + } + + /** + * Identifies an [Entity]. + * + * Retention: RUNTIME + * Target: CLASS + */ + data object EntityAnnotation : JMoleculesAnnotationSupplier { + override val feature = DDD + override fun spec(): KotlinAnnotationSpec = buildAnnotation(className("Entity")) + } + + /** + * Identifies a [Factory]. + * + * Retention: RUNTIME + * Target: CLASS + */ + data object FactoryAnnotation : JMoleculesAnnotationSupplier { + override val feature = DDD + override fun spec(): KotlinAnnotationSpec = buildAnnotation(className("Factory")) + } + + /** + * Declares a field (or a getter) of a class to constitute the identity of the corresponding class. + * + * Retention: RUNTIME + * Target: ANNOTATION_CLASS, FIELD, PROPERTY, PROPERTY_GETTER + */ + data object IdentityAnnotation : JMoleculesAnnotationSupplier { + override val feature = DDD + override fun spec(): KotlinAnnotationSpec = buildAnnotation(className("Identity")) + } + + + /** + * Identifies a [Repository]. + * + * Retention: RUNTIME + * Target: CLASS + */ + data object RepositoryAnnotation : JMoleculesAnnotationSupplier { + override val feature = DDD + override fun spec(): KotlinAnnotationSpec = buildAnnotation(className("Repository")) + } + + /** + * Identifies a domain [Service]. + * + * Retention: RUNTIME + * Target: CLASS + */ + data object ServiceAnnotation : JMoleculesAnnotationSupplier { + override val feature = DDD + override fun spec(): KotlinAnnotationSpec = buildAnnotation(className("Service")) + } + + /** + * Identifies a value object. Domain concepts that are modeled as value objects have no conceptual identity or + * lifecycle. Implementations should be immutable, operations on it are side effect free. + * + * Retention: RUNTIME + * Target: CLASS + */ + data object ValueObjectAnnotation : JMoleculesAnnotationSupplier { + override val feature = DDD + override fun spec(): KotlinAnnotationSpec = buildAnnotation(className("ValueObject")) + } +} diff --git a/axon-avro-generation/src/main/resources/META-INF/services/io.toolisticon.kotlin.generation.spi.KotlinCodeGenerationSpi b/axon-avro-generation/src/main/resources/META-INF/services/io.toolisticon.kotlin.generation.spi.KotlinCodeGenerationSpi index 3eb76ca..8ac7435 100644 --- a/axon-avro-generation/src/main/resources/META-INF/services/io.toolisticon.kotlin.generation.spi.KotlinCodeGenerationSpi +++ b/axon-avro-generation/src/main/resources/META-INF/services/io.toolisticon.kotlin.generation.spi.KotlinCodeGenerationSpi @@ -15,6 +15,8 @@ io.holixon.axon.avro.generation.strategy.AxonQueryProtocolInterfaceStrategy io.holixon.axon.avro.generation.processor.AxonRevisionAnnotationProcessor io.holixon.axon.avro.generation.processor.AxonTargetIdentifierAnnotationProcessor +io.holixon.axon.avro.generation.processor.JMoleculesAnnotationRecordTypeProcessor + ################################################################################ # logical types ################################################################################