Axon - AnnotationCommandHandlerBeanPostProcessor Spring config

Hi all,

I’m a noob to the Axon framework, really like the possibilities it presents, well done.

I’m attempting the “getting started” application using Spring’s Java configuration to configure my beans.
I’m using AnnotationCommandHandlerBeanPostProcessor to subscribe command handlers. It appears to me that it is not doing so or I have misconfigured something:

org.axonframework.commandhandling.NoHandlerForCommandException: No handler was subscribed to command [com.zaralab.axon.CreateToDoItemCommand]
at org.axonframework.commandhandling.SimpleCommandBus.findCommandHandlerFor(SimpleCommandBus.java:113)
at org.axonframework.commandhandling.SimpleCommandBus.doDispatch(SimpleCommandBus.java:102)
at org.axonframework.commandhandling.SimpleCommandBus.dispatch(SimpleCommandBus.java:70)
at org.axonframework.commandhandling.gateway.AbstractCommandGateway.sendAndForget(AbstractCommandGateway.java:86)
at org.axonframework.commandhandling.gateway.GatewayProxyFactory$DispatchOnInvocationHandler.invoke(GatewayProxyFactory.java:407)
at org.axonframework.commandhandling.gateway.GatewayProxyFactory$DispatchOnInvocationHandler.invoke(GatewayProxyFactory.java:367)
at org.axonframework.commandhandling.gateway.GatewayProxyFactory$FireAndForget.invoke(GatewayProxyFactory.java:570)
at org.axonframework.commandhandling.gateway.GatewayProxyFactory$NullOnTimeout.invoke(GatewayProxyFactory.java:475)
at org.axonframework.commandhandling.gateway.GatewayProxyFactory$NullOnInterrupted.invoke(GatewayProxyFactory.java:493)
at org.axonframework.commandhandling.gateway.GatewayProxyFactory$WrapNonDeclaredCheckedExceptions.invoke(GatewayProxyFactory.java:450)
at org.axonframework.commandhandling.gateway.GatewayProxyFactory$GatewayInvocationHandler.invoke(GatewayProxyFactory.java:350)

My Application config class:

@Configuration
@ComponentScan(basePackages = “com.zaralab.axon”)
@EnableAutoConfiguration
public class Application {

public static void main(String[] args) {

ApplicationContext applicationContext = SpringApplication.run(Application.class, args);
for (String name : applicationContext.getBeanDefinitionNames()) {
System.out.println("Spring Bean : " + name);
}
}

@Bean
public CommandBus commandBus() {
CommandBus commandBus = new SimpleCommandBus();
return commandBus;
}

@Bean
public CommandGatewayFactoryBean commandGateway() {
CommandGatewayFactoryBean commandGatewayFactoryBean = new CommandGatewayFactoryBean();
commandGatewayFactoryBean.setCommandBus(commandBus());
return commandGatewayFactoryBean;
}

@Bean
public EventStore eventStore() {
EventStore eventStore = new FileSystemEventStore(new SimpleEventFileResolver(new File("./events")));
return eventStore;
}

@Bean
public EventBus eventBus() {
EventBus eventBus = new SimpleEventBus();
return eventBus;
}

@Bean
public EventSourcingRepository eventSourcingRepository() {
EventSourcingRepository eventSourcingRepository = new EventSourcingRepository(ToDoItem.class, eventStore());
eventSourcingRepository.setEventBus(eventBus());
return eventSourcingRepository;
}

@Bean
public AnnotationCommandHandlerBeanPostProcessor annotationCommandHandlerBeanPostProcessor() throws Exception {
AnnotationCommandHandlerBeanPostProcessor annotationCommandHandlerBeanPostProcessor = new AnnotationCommandHandlerBeanPostProcessor();
annotationCommandHandlerBeanPostProcessor.setCommandBus(commandBus());
return annotationCommandHandlerBeanPostProcessor;
}

@Bean
public AnnotationEventListenerBeanPostProcessor annotationEventListenerBeanPostProcessor() {
AnnotationEventListenerBeanPostProcessor annotationEventListenerBeanPostProcessor = new AnnotationEventListenerBeanPostProcessor();
annotationEventListenerBeanPostProcessor.setEventBus(eventBus());
return annotationEventListenerBeanPostProcessor;
}

}

ToDoItem :

@Component
public class ToDoItem extends AbstractAnnotatedAggregateRoot {

@AggregateIdentifier
private String id;

public ToDoItem() {
}

@CommandHandler
public ToDoItem(CreateToDoItemCommand command) {
apply(new ToDoItemCreatedEvent(command.getTodoId(), command.getDescription()));
}

@EventHandler
public void on(ToDoItemCreatedEvent event) {
this.id = event.getTodoId();
}

@CommandHandler
public void markCompleted(MarkCompletedCommand command) {
apply(new ToDoItemCompletedEvent(id));
}

}

I’ve annotated with @CommandHandler for Axon & annotated class with @Component for Spring.
The beans are in my context but I still get the above error. Could someone help point out the problem please.

Beans in Spring context:

Spring Bean : org.springframework.context.annotation.internalConfigurationAnnotationProcessor
Spring Bean : org.springframework.context.annotation.internalAutowiredAnnotationProcessor
Spring Bean : org.springframework.context.annotation.internalRequiredAnnotationProcessor
Spring Bean : org.springframework.context.annotation.internalCommonAnnotationProcessor
Spring Bean : application
Spring Bean : org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor
Spring Bean : org.springframework.context.annotation.ConfigurationClassPostProcessor.enhancedConfigurationProcessor
Spring Bean : toDoEventHandler
Spring Bean : toDoItem
Spring Bean : toDoItemController
Spring Bean : annotationEventListenerBeanPostProcessor
Spring Bean : annotationCommandHandlerBeanPostProcessor
Spring Bean : eventBus
Spring Bean : commandBus
Spring Bean : commandGateway
Spring Bean : eventStore
Spring Bean : eventSourcingRepository
Spring Bean : org.springframework.boot.autoconfigure.AutoConfigurationPackages
Spring Bean : org.springframework.boot.autoconfigure.MessageSourceAutoConfiguration
Spring Bean : messageSource
Spring Bean : org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration
Spring Bean : propertySourcesPlaceholderConfigurer
Spring Bean : org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration$EmbeddedTomcat
Spring Bean : tomcatEmbeddedServletContainerFactory
Spring Bean : org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration
Spring Bean : embeddedServletContainerCustomizerBeanPostProcessor
Spring Bean : org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration$DispatcherServletConfiguration
Spring Bean : dispatcherServlet
Spring Bean : dispatcherServletRegistration
Spring Bean : org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration
Spring Bean : org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter$FaviconConfiguration
Spring Bean : faviconHandlerMapping
Spring Bean : faviconRequestHandler
Spring Bean : org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration
Spring Bean : requestMappingHandlerMapping
Spring Bean : mvcContentNegotiationManager
Spring Bean : viewControllerHandlerMapping
Spring Bean : beanNameHandlerMapping
Spring Bean : resourceHandlerMapping
Spring Bean : defaultServletHandlerMapping
Spring Bean : requestMappingHandlerAdapter
Spring Bean : mvcConversionService
Spring Bean : mvcValidator
Spring Bean : mvcUriComponentsContributor
Spring Bean : httpRequestHandlerAdapter
Spring Bean : simpleControllerHandlerAdapter
Spring Bean : handlerExceptionResolver
Spring Bean : org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter
Spring Bean : defaultViewResolver
Spring Bean : requestContextListener
Spring Bean : viewResolver
Spring Bean : org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration
Spring Bean : hiddenHttpMethodFilter
Spring Bean : org.springframework.context.annotation.MBeanExportConfiguration
Spring Bean : mbeanExporter
Spring Bean : org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration$MBeanExport
Spring Bean : org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration
Spring Bean : org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration$ObjectMappers
Spring Bean : jacksonObjectMapper
Spring Bean : mappingJackson2HttpMessageConverter
Spring Bean : http.mappers.CONFIGURATION_PROPERTIES
Spring Bean : org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor
Spring Bean : org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration
Spring Bean : messageConverters
Spring Bean : org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration
Spring Bean : serverProperties

Thanks for your assistance.

Roscoe Lotriet

Hi Roscoe,

you don’t have to annotate the aggregate root with @Component. It’s not a Spring managed bean. Instead, you should define a bean of type AggregateAnnotationCommandHandler. It acts as the command handler on behalf of the aggregate, and loads the correct instance to invoke automatically.

Hope this helps.
Cheers,

Allard

Hi Allard,

Thanks for the response & sorry about the late reply. Your solution worked :slight_smile:

Regards,
Roscoe Lotriet