1
votes

I am trying to migrate my application to Axon 4.0 with Axon server. Here is my code.

data class CreateTravelProductCommand(
    @TargetAggregateIdentifier val id: String,
    val productCreator: String
)

val id: String = ObjectId.get().toString()
val command = CreateTravelProductCommand(id=id, productCreator=request.creator)
commandGateway.sendAndWait(command)

But I got this error with my command.

org.axonframework.commandhandling.distributed.CommandDispatchException: The command [com.sunday.api.product.CreateTravelProductCommand] does not contain a routing key. at org.axonframework.commandhandling.distributed.AbstractRoutingStrategy.getRoutingKey(AbstractRoutingStrategy.java:57) ~[axon-messaging-4.0.jar:4.0] at org.axonframework.axonserver.connector.command.AxonServerCommandBus.dispatch(AxonServerCommandBus.java:114) ~[axon-server-connector-4.0.jar:4.0] at org.axonframework.commandhandling.gateway.AbstractCommandGateway.send(AbstractCommandGateway.java:75) [axon-messaging-4.0.jar:4.0] at org.axonframework.commandhandling.gateway.DefaultCommandGateway.send(DefaultCommandGateway.java:78) [axon-messaging-4.0.jar:4.0] at org.axonframework.commandhandling.gateway.DefaultCommandGateway.sendAndWait(DefaultCommandGateway.java:96) [axon-messaging-4.0.jar:4.0] at com.sunday.underwriting.product.ProductHandler.sendCreateProductCommand(ProductHandler.kt:40) [classes/:na] at com.sunday.underwriting.product.ProductHandler.access$sendCreateProductCommand(ProductHandler.kt:33) [classes/:na] at com.sunday.underwriting.product.ProductHandler$createProduct$product$1.invoke(ProductHandler.kt:97) [classes/:na] at com.sunday.underwriting.product.ProductHandler$createProduct$product$1.invoke(ProductHandler.kt:33) [classes/:na] at com.sunday.underwriting.product.ProductHandler$sam$java_util_function_Function$0.apply(ProductHandler.kt) [classes/:na] at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:100) [reactor-core-3.2.2.RELEASE.jar:3.2.2.RELEASE] at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:73) [reactor-core-3.2.2.RELEASE.jar:3.2.2.RELEASE] at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1476) [reactor-core-3.2.2.RELEASE.jar:3.2.2.RELEASE] at reactor.core.publisher.MonoSingle$SingleSubscriber.onComplete(MonoSingle.java:171) [reactor-core-3.2.2.RELEASE.jar:3.2.2.RELEASE] at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:136) [reactor-core-3.2.2.RELEASE.jar:3.2.2.RELEASE] at reactor.core.publisher.FluxFlatMap$FlatMapMain.checkTerminated(FluxFlatMap.java:794) [reactor-core-3.2.2.RELEASE.jar:3.2.2.RELEASE] at reactor.core.publisher.FluxFlatMap$FlatMapMain.drainLoop(FluxFlatMap.java:560) [reactor-core-3.2.2.RELEASE.jar:3.2.2.RELEASE] at reactor.core.publisher.FluxFlatMap$FlatMapMain.drain(FluxFlatMap.java:540) [reactor-core-3.2.2.RELEASE.jar:3.2.2.RELEASE] at reactor.core.publisher.FluxFlatMap$FlatMapMain.onComplete(FluxFlatMap.java:426) [reactor-core-3.2.2.RELEASE.jar:3.2.2.RELEASE] at reactor.core.publisher.DrainUtils.postCompleteDrain(DrainUtils.java:131) [reactor-core-3.2.2.RELEASE.jar:3.2.2.RELEASE] at reactor.core.publisher.DrainUtils.postComplete(DrainUtils.java:186) [reactor-core-3.2.2.RELEASE.jar:3.2.2.RELEASE] at reactor.core.publisher.FluxMapSignal$FluxMapSignalSubscriber.onComplete(FluxMapSignal.java:213) [reactor-core-3.2.2.RELEASE.jar:3.2.2.RELEASE] at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:136) [reactor-core-3.2.2.RELEASE.jar:3.2.2.RELEASE] at reactor.core.publisher.FluxPeek$PeekSubscriber.onComplete(FluxPeek.java:252) [reactor-core-3.2.2.RELEASE.jar:3.2.2.RELEASE] at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:136) [reactor-core-3.2.2.RELEASE.jar:3.2.2.RELEASE] at reactor.netty.channel.FluxReceive.terminateReceiver(FluxReceive.java:378) [reactor-netty-0.8.2.RELEASE.jar:0.8.2.RELEASE] at reactor.netty.channel.FluxReceive.drainReceiver(FluxReceive.java:202) [reactor-netty-0.8.2.RELEASE.jar:0.8.2.RELEASE] at reactor.netty.channel.FluxReceive.onInboundComplete(FluxReceive.java:343) [reactor-netty-0.8.2.RELEASE.jar:0.8.2.RELEASE] at reactor.netty.channel.ChannelOperations.onInboundComplete(ChannelOperations.java:325) [reactor-netty-0.8.2.RELEASE.jar:0.8.2.RELEASE] at reactor.netty.http.server.HttpServerOperations.onInboundNext(HttpServerOperations.java:442) [reactor-netty-0.8.2.RELEASE.jar:0.8.2.RELEASE] at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:141) [reactor-netty-0.8.2.RELEASE.jar:0.8.2.RELEASE] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [netty-transport-4.1.29.Final.jar:4.1.29.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [netty-transport-4.1.29.Final.jar:4.1.29.Final] at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) [netty-transport-4.1.29.Final.jar:4.1.29.Final] at reactor.netty.http.server.HttpTrafficHandler.channelRead(HttpTrafficHandler.java:188) [reactor-netty-0.8.2.RELEASE.jar:0.8.2.RELEASE] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [netty-transport-4.1.29.Final.jar:4.1.29.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [netty-transport-4.1.29.Final.jar:4.1.29.Final] at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) [netty-transport-4.1.29.Final.jar:4.1.29.Final] at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:438) [netty-transport-4.1.29.Final.jar:4.1.29.Final] at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:310) [netty-codec-4.1.29.Final.jar:4.1.29.Final] at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:284) [netty-codec-4.1.29.Final.jar:4.1.29.Final] at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:253) [netty-transport-4.1.29.Final.jar:4.1.29.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [netty-transport-4.1.29.Final.jar:4.1.29.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [netty-transport-4.1.29.Final.jar:4.1.29.Final] at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) [netty-transport-4.1.29.Final.jar:4.1.29.Final] at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1434) [netty-transport-4.1.29.Final.jar:4.1.29.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [netty-transport-4.1.29.Final.jar:4.1.29.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [netty-transport-4.1.29.Final.jar:4.1.29.Final] at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:965) [netty-transport-4.1.29.Final.jar:4.1.29.Final] at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163) [netty-transport-4.1.29.Final.jar:4.1.29.Final] at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:628) [netty-transport-4.1.29.Final.jar:4.1.29.Final] at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:563) [netty-transport-4.1.29.Final.jar:4.1.29.Final] at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:480) [netty-transport-4.1.29.Final.jar:4.1.29.Final] at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:442) [netty-transport-4.1.29.Final.jar:4.1.29.Final] at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:884) [netty-common-4.1.29.Final.jar:4.1.29.Final] at java.lang.Thread.run(Thread.java:748) [na:1.8.0_172]

Edit:

I just found out that if you keep the class in the same project, it is ok.

The problem is when you import the class from another project (Which used to work prior to axon server)

For example:

My project has dependencies of another project called api.

dependencies {
    compile project(':api')
}

If the class is declared in the api project, axon server library will throw error that it cannot find routing key. But if the class is declared in the main project it self, it works as expected. I think I should file this issue on github.

3

3 Answers

1
votes

The real issue is version mismatched between 2 projects. I had to correct version but intellij autoloader didn't work and the api project had the incorrect version.

I apologize for my stupidity

1
votes

I got the same problem when migrating from Axon 3.x to 4.0. The solution was related to the @TargetAggregateIdentifier - I was missing it off the 'CreateXXXCommand' that's handled by my aggregate. I'm pretty sure that adding @TargetAggregateIdentifier wasn't necessary for create commands (since it doesn't have to locate an existing aggregate) in Axon 3.x

At time of writing the Migration guide is incomplete https://docs.axoniq.io/reference-guide/3-migration/migration-guide

0
votes

This is actually more related to Kotlin than Axon. Axon expects them on the Field or Getter method. Apparently, that's not where Kotlin places them be default.

Check out https://kotlinlang.org/docs/reference/annotations.html#annotation-use-site-targets

You probably need to annotate the property with @get:TargetAggregateIdentifier