Snapshotter using spring annotation config returns NullPointerException

364 views
Skip to first unread message

Sivarajan Parasuraman

unread,
Jun 3, 2015, 4:54:07 AM6/3/15
to axonfr...@googlegroups.com
I'm trying to migrate the spring xml configuration to annotated way and facing this issue once the thread pool executor calls the snapshotter. Not sure why it happens as it worked well with spring xml configuration. 

Pls help me in resolving this since I'm stuck for a long time due to Nullpointer exception from framework.

Exception stacktrace while snapshotter executes is as follows,
2939 [taskExecutor-1] DEBUG org.hibernate.loader.Loader  - Result row: 
2939 [taskExecutor-1] TRACE org.hibernate.type.descriptor.sql.BasicExtractor  - Found [034ddfde-ddf3-4fb4-95d6-fb5974b3ed77] as column [col_0_0_]
2939 [taskExecutor-1] TRACE org.hibernate.type.descriptor.sql.BasicExtractor  - Found [5ee497d1-49f9-4e7c-a876-48cd499ebc89] as column [col_1_0_]
2939 [taskExecutor-1] TRACE org.hibernate.type.descriptor.sql.BasicExtractor  - Found [16] as column [col_2_0_]
2939 [taskExecutor-1] TRACE org.hibernate.type.descriptor.sql.BasicExtractor  - Found [2015-06-03T14:07:46.185+05:30] as column [col_3_0_]
2939 [taskExecutor-1] TRACE org.hibernate.type.descriptor.sql.BasicExtractor  - Found [com.sas.axon.api.CreateToDoItemEvent] as column [col_4_0_]
2939 [taskExecutor-1] TRACE org.hibernate.type.descriptor.sql.BasicExtractor  - Found [null] as column [col_5_0_]
2939 [taskExecutor-1] TRACE org.hibernate.type.descriptor.sql.BasicExtractor  - Found [[B@178a924] as column [col_6_0_]
2939 [taskExecutor-1] TRACE org.hibernate.type.descriptor.sql.BasicExtractor  - Found [[B@a88cad] as column [col_7_0_]
2941 [taskExecutor-1] DEBUG org.springframework.orm.jpa.JpaTransactionManager  - Initiating transaction rollback
2941 [taskExecutor-1] DEBUG org.springframework.orm.jpa.JpaTransactionManager  - Rolling back JPA transaction on EntityManager [org.hibernate.ejb.EntityManagerImpl@4869dc]
2941 [taskExecutor-1] DEBUG org.hibernate.engine.transaction.spi.AbstractTransactionImpl  - rolling back
2941 [taskExecutor-1] DEBUG org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction  - rolled JDBC Connection
2941 [taskExecutor-1] DEBUG org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction  - re-enabling autocommit
2942 [taskExecutor-1] DEBUG org.springframework.orm.jpa.JpaTransactionManager  - Closing JPA EntityManager [org.hibernate.ejb.EntityManagerImpl@4869dc] after transaction
2942 [taskExecutor-1] DEBUG org.springframework.orm.jpa.EntityManagerFactoryUtils  - Closing JPA EntityManager
2942 [taskExecutor-1] DEBUG org.hibernate.engine.jdbc.internal.LogicalConnectionImpl  - Releasing JDBC connection
2942 [taskExecutor-1] DEBUG com.mchange.v2.resourcepool.BasicResourcePool  - trace com.mchange.v2.resourcepool.BasicResourcePool@1bbb378 [managed: 5, unused: 4, excluded: 0] (e.g. com.mchange.v2.c3p0.impl.NewPooledConnection@171d828)
2942 [taskExecutor-1] DEBUG org.hibernate.engine.jdbc.internal.LogicalConnectionImpl  - Released JDBC connection
2943 [taskExecutor-1] WARN  org.axonframework.eventsourcing.AbstractSnapshotter  - An attempt to create and store a snapshot resulted in an exception:
java.lang.NullPointerException
at org.axonframework.eventsourcing.AggregateSnapshotter.createSnapshot(AggregateSnapshotter.java:45)
at org.axonframework.eventsourcing.AbstractSnapshotter$CreateSnapshotTask.run(AbstractSnapshotter.java:194)
at org.axonframework.eventsourcing.AbstractSnapshotter$TransactionalRunnableWrapper.run(AbstractSnapshotter.java:144)
at org.axonframework.eventsourcing.AbstractSnapshotter$SilentTask.run(AbstractSnapshotter.java:164)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)


Below is my configuration,

public class DatabaseConfig {
...
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) throws PropertyVetoException{
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
jpaTransactionManager.setEntityManagerFactory(entityManagerFactory);
return jpaTransactionManager;
}
...
}

@Import(DatabaseConfig.class)
public class ApplicationConfig {

@Autowired
DatabaseConfig databaseConfig;

@Autowired
private PlatformTransactionManager transactionManager;
@Bean
public CommandGatewayFactoryBean<CommandGateway> commandGatewayFactoryBean() {
CommandGatewayFactoryBean<CommandGateway> factory = new CommandGatewayFactoryBean<CommandGateway>();
factory.setCommandBus(commandBus());
return factory;
}

@Bean
public MyCommandHandler myCommandHandler() {
MyCommandHandler commandHandler = new MyCommandHandler();
commandHandler.setCartIdRepository(databaseConfig.jpaCartIdRepository());
commandHandler.setRepository(repository());
return commandHandler;
}

@Bean
public CommandBus commandBus() {
SimpleCommandBus simpleCommandBus = new SimpleCommandBus();
simpleCommandBus.setTransactionManager(new SpringTransactionManager(transactionManager));
return simpleCommandBus;
}

@Bean(name="taskExecutor")
public ThreadPoolTaskExecutor taskExecutor(){
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setMaxPoolSize(5);
threadPoolTaskExecutor.setCorePoolSize(2);
threadPoolTaskExecutor.setWaitForTasksToCompleteOnShutdown(true);
return threadPoolTaskExecutor;
}

@Bean
AnnotationCommandHandlerBeanPostProcessor annotationCommandHandlerBeanPostProcessor() {
AnnotationCommandHandlerBeanPostProcessor handler = new AnnotationCommandHandlerBeanPostProcessor();
handler.setCommandBus(commandBus());
return handler;
}
@Bean
public JpaEventStore eventStore() {
return new JpaEventStore(entityManagerProvider(),serializer());
}
@Bean
public Serializer serializer(){
return new JacksonSerializer();
}
@Bean
public EventBus eventBus() {
return new SimpleEventBus();
}

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

@Bean
public EventSourcingRepository<MyAggregate> repository() {
EventSourcingRepository<MyAggregate> repository = new EventSourcingRepository<MyAggregate>(MyAggregate.class, eventStore());
repository.setEventBus(eventBus());
repository.setSnapshotterTrigger(snapshotterTrigger());
return repository;
}

@Bean
public EventCountSnapshotterTrigger snapshotterTrigger(){
EventCountSnapshotterTrigger snapshotterTrigger = new EventCountSnapshotterTrigger();
snapshotterTrigger.setSnapshotter(snapshotter());
snapshotterTrigger.setTrigger(5);
return snapshotterTrigger;
}

@Bean
public SpringAggregateSnapshotter snapshotter(){
SpringAggregateSnapshotter snapshotter = new SpringAggregateSnapshotter();
snapshotter.setEventStore(eventStore());
snapshotter.setExecutor(taskExecutor());
snapshotter.setTransactionManager(transactionManager);
return snapshotter;
}
@Bean
public EntityManagerProvider entityManagerProvider() {
return new ContainerManagedEntityManagerProvider();
}

}

It does not store the snapshot entry into the database and results in exception before that. Pls guide if am doing something wrong.

Thanks.

Allard Buijze

unread,
Jun 3, 2015, 5:09:35 AM6/3/15
to Axon Framework Users
Hi,

a quick glance at the source code reveals that there isn't any "aggregateFactory" configured with the snapshotter. That's strange, because the SpringAggregateSnapshotter will automatically load them from the application context in the "afterPropertiesSet" method.
I see two things that can go wrong. Either Spring doesn't invoke the afterPropertiesSet method, or the method is invoked at a time when not all beans are available in the application context yet. The first could be by design, or a bug in Spring.

In your case, the workaround would be to add a parameter to your method of type List<AggregateFactory>. Then pass the value of this argument to the setAggregateFactories() on the snapshotter.
If you can, please check whether Spring invokes the afterPropertiesSet method, and whether that method finds any aggregate factories. That's valuable information for a potential fix/workaround in Axon.

Cheers,

Allard

--
You received this message because you are subscribed to the Google Groups "Axon Framework Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to axonframewor...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Sivarajan Parasuraman

unread,
Jun 3, 2015, 11:08:23 AM6/3/15
to axonfr...@googlegroups.com
Hi Allard,

Tried the workaround mentioned but it is not working.

Parameterized approach to the method required various parameters to be added in nested method calls. Even then it resulted in same null pointer and was not able to load from the context.
Unable to autowire/create the aggregateFactoryList that is required and tried various implementations. Not sure in which way we can externally specify the aggregate factory in the context configuration.

Thanks for your time and pls help on resolving this. 

Allard Buijze

unread,
Jun 5, 2015, 1:27:38 PM6/5/15
to axonfr...@googlegroups.com
You can create an AggregateFactory simply by doing new GenericAggregateFactory(MyAggregateClass.class);
Unless tou use custom aggregate factories, adding those to the list (setAggregateFactories) should resolve the problem.

Sivarajan Parasuraman

unread,
Jun 9, 2015, 4:03:37 AM6/9/15
to axonfr...@googlegroups.com
Hi Allard,

Thanks for your time and the fix mentioned worked. Now, spring is able to load the aggregate factory context.

Lukáš Vasek

unread,
Feb 18, 2016, 5:39:54 AM2/18/16
to Axon Framework Users
Hi Allard,
What in case when we have maven project which is constructed with multiple subprojects. In infrastructure project we have configured SpringAggregateSnapshotter so it is impossible to view other aggregates here. And if I wire snapshotter to other modules, there's no method to add factory to it.
Is it ok to create SpringAggregateSnapshotter in each module in which we want snapshots?

Thanks

Lukas

Allard Buijze

unread,
Feb 25, 2016, 5:54:54 AM2/25/16
to Axon Framework Users
Hi Lukas,

yes, you can have multiple SpringAggregateSnapshotter instances. However, even in multi-module projects, a single instance should be able to do the job. That's because Spring does the discovery at runtime, where all modules are available.
Generally, I put the Snapshotter in a generic "infrastructure" module, where also the CommandBus and EventBus implementations are configures. Each module will have a dependency on that module. At runtime, the Snapshotter will then automatically detect all aggregate related infrastructure from the different components that are available at runtime.

Cheers,

Allard

--

Lukáš Vasek

unread,
Feb 28, 2016, 2:48:41 PM2/28/16
to Axon Framework Users
Hi Allard,

but that way it's not working (or I have misconfigured something).

In infrastructure module config I have this:

@Bean
Snapshotter snapshotter(SnapshotEventStore snapshotEventStore) {

SpringAggregateSnapshotter snapshotter = new SpringAggregateSnapshotter();
    snapshotter.setEventStore(snapshotEventStore);
snapshotter.setExecutor(axonExecutor());
return snapshotter;
}

@Bean
SnapshotterTrigger snapshottrigger(Snapshotter snapshotter) {

EventCountSnapshotterTrigger snapshotterTrigger = new EventCountSnapshotterTrigger();
    snapshotterTrigger.setTrigger(10);
snapshotterTrigger.setSnapshotter(snapshotter);
return snapshotterTrigger;
}


and then in Accessor module I have this

@Bean
AggregateFactory<AccessorAggregateRoot> accessorAggregateFactory() {
return new GenericAggregateFactory<AccessorAggregateRoot>(AccessorAggregateRoot.class);
}

@Bean(name = "accessorRepository")
EventSourcingRepository<AccessorAggregateRoot> accessorEventSourcingRepository(EventBus eventBus, SnapshotEventStore eventStore, SnapshotterTrigger snapshotterTrigger) {
EventSourcingRepository<AccessorAggregateRoot> eventSourcingRepository = new EventSourcingRepository<AccessorAggregateRoot>(accessorAggregateFactory(), eventStore);
eventSourcingRepository.setEventBus(eventBus);
eventSourcingRepository.setSnapshotterTrigger(snapshotterTrigger);
return eventSourcingRepository;
}

but snapshots are never created :(

In SpringAggregateSnapshotter.afterPropertiesSet the factory for AccessorAggregateRoot is found.

Am I doing something wrong?

Thanks

Allard Buijze

unread,
Mar 9, 2016, 3:48:15 PM3/9/16
to Axon Framework Users
Hi,

sorry for the late reply. 
It doesn't seem you have configured a TransactionManager on your snapshotter. Since it's configured to be asynchronous, it cannot use the transaction of the command handling thread. It needs its own.
snapshotter.setTransactionManager(txManager); should do the trick.

Cheers,

Allard

Lukáš Vasek

unread,
Mar 10, 2016, 3:43:33 AM3/10/16
to Axon Framework Users
Hi Allard,
So I've tried to add transactionmanager, but that didn't helped.

@Bean
Snapshotter snapshotter(SnapshotEventStore snapshotEventStore, JpaTransactionManager transactionManager, ApplicationContext applicationContext) {

SpringAggregateSnapshotter snapshotter = new SpringAggregateSnapshotter();
snapshotter.setEventStore(snapshotEventStore);
snapshotter.setExecutor(axonExecutor());
    snapshotter.setTransactionManager(transactionManager);
snapshotter.setApplicationContext(applicationContext);
/*
try {
snapshotter.afterPropertiesSet();
} catch (Exception e) {
throw new RuntimeException(e);
}
*/
return snapshotter;
}

@Bean
SnapshotterTrigger snapshotterTrigger(Snapshotter snapshotter) {

EventCountSnapshotterTrigger snapshotterTrigger = new EventCountSnapshotterTrigger();
snapshotterTrigger.setTrigger(10);
snapshotterTrigger.setSnapshotter(snapshotter);
return snapshotterTrigger;
}

I guess that problem is within snapshotter.afterPropertiesSet - where is registration of factories. In the time when afterPropertiesSet is invoked (commented in my example) no factories exists. And unfortunately I don't see simple  way how to  add factories to snapshotter.


Allard Buijze

unread,
Mar 10, 2016, 5:23:44 AM3/10/16
to Axon Framework Users
It must be a timing thing. afterPropertiesSet might indeed kick in too early. Perhaps you can add a @DependsOn annotation on the snapshotter to force it to wait until the repositories have been created?

You can set the factories using: snapshotter.setAggregateFactories(...). Note that each EventSourcingRepository exposes the factory used to create (empty) instances of aggregates.

I will record a little design improvement in the issue tracker. This should be easier...


Lukáš Vasek

unread,
Mar 10, 2016, 8:19:50 AM3/10/16
to Axon Framework Users
Allard,
even if I add @DependsOn to snapshotter, snapshots are never crated. During debugging I can see that afterPropertiesSet is invoked automatically, so I've removed afterPropertiesSet from snapshotter. The factories are found, but no eventsourcing repositories. I don't know if this can be a problem.

INFRASTRUCTURE.AxonConfiguration.java
////////////////
/// SNAPSHOT ///
////////////////

@Bean
@DependsOn(value = {"accessorAggregateFactory"})

Snapshotter snapshotter(SnapshotEventStore snapshotEventStore, JpaTransactionManager transactionManager, ApplicationContext applicationContext) {
SpringAggregateSnapshotter snapshotter = new SpringAggregateSnapshotter();
snapshotter.setEventStore(snapshotEventStore);
snapshotter.setExecutor(axonExecutor());
snapshotter.setTransactionManager(transactionManager);
snapshotter.setApplicationContext(applicationContext);
    return snapshotter;
}


@Bean
SnapshotterTrigger snapshotterTrigger(Snapshotter snapshotter) {
EventCountSnapshotterTrigger snapshotterTrigger = new EventCountSnapshotterTrigger();
snapshotterTrigger.setTrigger(10);
snapshotterTrigger.setSnapshotter(snapshotter);
return snapshotterTrigger;
}

ACCESSOR-COMMAND.AccessorCommandConfiguration.java
@Bean(name = "accessorAggregateFactory")

AggregateFactory<AccessorAggregateRoot> accessorAggregateFactory() {
return new GenericAggregateFactory<AccessorAggregateRoot>(AccessorAggregateRoot.class);
}

@Bean(name = ACCESSOR_REPOSITORY)

EventSourcingRepository<AccessorAggregateRoot> accessorEventSourcingRepository(EventBus eventBus, SnapshotEventStore eventStore, SnapshotterTrigger snapshotterTrigger) {
    EventSourcingRepository<AccessorAggregateRoot> repository = new EventSourcingRepository<AccessorAggregateRoot>(accessorAggregateFactory(), eventStore);
repository.setEventBus(eventBus);
repository.setSnapshotterTrigger(snapshotterTrigger);
return repository;
}


If you need some debug informations, just let me know.

Thanks

PS: @DependsOn is ugly to have in infrastructure configuration (it shouldn't know about other modules). 




Allard Buijze

unread,
Mar 17, 2016, 9:05:13 AM3/17/16
to Axon Framework Users
Did you try adding a "List<EventSourcingRepository>" to your @Bean method's parameter list? Each EventSourcingRepository instance provides access to the AggregateFactory used to create new instances. This should also force Spring to initialize these repositories before creating the snapshotter.

Cheers,

Allard

Lukáš Vasek

unread,
Jul 26, 2016, 1:25:10 PM7/26/16
to Axon Framework Users
Hi Allard,
back to this issue ... I wasn't working on project long time. I suppose you are talking about snapshotter method. I cannot inject "List<EventSourcingRepository>" there, because then I have circular dependency. Any other hint how to solve this? (I'm still on axon 2.4)

Thanks

Allard Buijze

unread,
Jul 26, 2016, 4:24:23 PM7/26/16
to Axon Framework Users
Hi Lukas,

hmm. I guess this asks for a workaround and a solid fix. You can configure a separate list of aggregate factories. If you use the defaults, you can use the GenericAggregateFactory(MyAggregate.class). That should resolve the timing issues.

Meanwhile, I will figure out a way to change the timing of the AggregateFactory.

Cheers,

Allard

--

Lukáš Vasek

unread,
Sep 20, 2016, 7:23:09 AM9/20/16
to Axon Framework Users
Hi Allard,
were you able to look at the timing of AggregateFactory bean?

Thanks

Allard Buijze

unread,
Oct 5, 2016, 9:08:48 AM10/5/16
to Axon Framework Users
Hi Lukas,

yes, a colleague has provided a fix in the 2.4 branch. In 3.0, things work a bit differently anyway, so we don't expect this issue to occur.

We are currently evaluating when to release 2.4.6.

Cheers,

Allard

--
Reply all
Reply to author
Forward
0 new messages