Class not found exception when firing a scheduled event

Hi,

I’m having issues with firing scheduled events…

  • Using Quartz scheduler with MongoDB (using https://github.com/michaelklishin/quartz-mongodb for putting the scheduled jobs in MongoDB)
  • All events, sagas etc are stored in MongoDB, also all our “views/projections” are stored in MongoDB
  • Axon 3.2 is used

I have a saga, that sends data to a SOAP based service, but if the service call fails (e.g. due to timeout errors), I schedule an event to try the request again at a later time.
The job gets scheduled OK in the quartz mongodb collections.

When time passes and the rescheduled event is triggered I get the following error(s):

java.lang.ClassNotFoundException: com.mn.stagportal.domain.events.ChangeEmploymentRetriedEvent
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:338)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:682)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1859)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1745)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2033)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1567)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2278)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2202)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2060)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1567)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2278)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2202)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2060)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1567)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:427)
at java.util.HashMap.readObject(HashMap.java:1409)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1158)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2169)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2060)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1567)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:427)
at com.novemberain.quartz.mongodb.util.SerialUtils.stringMapFromBytes(SerialUtils.java:85)
at com.novemberain.quartz.mongodb.util.SerialUtils.deserialize(SerialUtils.java:62)
at com.novemberain.quartz.mongodb.JobDataConverter.toJobDataFromBase64(JobDataConverter.java:86)
at com.novemberain.quartz.mongodb.JobDataConverter.toJobData(JobDataConverter.java:65)
at com.novemberain.quartz.mongodb.JobConverter.createJobDataMap(JobConverter.java:76)
at com.novemberain.quartz.mongodb.JobConverter.toJobDetail(JobConverter.java:58)
at com.novemberain.quartz.mongodb.dao.JobDao.retrieveJob(JobDao.java:113)
at com.novemberain.quartz.mongodb.TriggerRunner.retrieveJob(TriggerRunner.java:227)
at com.novemberain.quartz.mongodb.TriggerRunner.createTriggerFiredBundle(TriggerRunner.java:184)
at com.novemberain.quartz.mongodb.TriggerRunner.triggersFired(TriggerRunner.java:83)
at com.novemberain.quartz.mongodb.MongoDBJobStore.triggersFired(MongoDBJobStore.java:431)
at org.quartz.core.QuartzSchedulerThread.run(QuartzSchedulerThread.java:336)

2018-04-05 09:43:29.752 [schedulerFactoryBean_Worker-1] ERROR o.a.e.scheduling.quartz.FireEventJob - Exception occurred while publishing scheduled event [com.mn.stagportal.domain.events.ChangeEmploymentRetriedEvent]
java.lang.NullPointerException: null
at org.axonframework.messaging.GenericMessage.(GenericMessage.java:74)
at org.axonframework.messaging.GenericMessage.(GenericMessage.java:56)
at org.axonframework.eventhandling.GenericEventMessage.(GenericEventMessage.java:83)
at org.axonframework.eventhandling.scheduling.quartz.FireEventJob.createMessage(FireEventJob.java:107)
at org.axonframework.eventhandling.scheduling.quartz.FireEventJob.execute(FireEventJob.java:71)
at org.quartz.core.JobRunShell.run(JobRunShell.java:202)
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573)

2018-04-05 09:43:29.752 [schedulerFactoryBean_Worker-1] INFO org.quartz.core.JobRunShell - Job STAG-Events.event-8bfc3d56-fe0c-4c03-b487-0a46baac911f threw a JobExecutionException:
org.quartz.JobExecutionException: java.lang.NullPointerException
at org.axonframework.eventhandling.scheduling.quartz.FireEventJob.execute(FireEventJob.java:90)
at org.quartz.core.JobRunShell.run(JobRunShell.java:202)
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573)
Caused by: java.lang.NullPointerException: null
at org.axonframework.messaging.GenericMessage.(GenericMessage.java:74)
at org.axonframework.messaging.GenericMessage.(GenericMessage.java:56)
at org.axonframework.eventhandling.GenericEventMessage.(GenericEventMessage.java:83)
at org.axonframework.eventhandling.scheduling.quartz.FireEventJob.createMessage(FireEventJob.java:107)
at org.axonframework.eventhandling.scheduling.quartz.FireEventJob.execute(FireEventJob.java:71)
… 2 common frames omitted

Weird thing is, that when I run my application from IntelliJ this error does NOT occur. Only when I run the compiled springboot app from the commandline.
As far as I can detemine, the class com.mn.stagportal.domain.events.ChangeEmploymentRetriedEvent is on the classpath (it’s in the compiled springboot app.jar).

So I’m lost why the class is not found…

Thanks,

Danny

Hi Danny,

I haven’t seen this issue before. Did you set a classloader in your Quartz configuration? Generally, I use the BeanClassLoader (which Spring uses to initialize the beans) as the loader for quartz.

Note that the NPE is cause by the fact that the event details could not be retrieved from the JobDataMap, in which case apparently Quartz returns null, which is not allowed as a payload in the Generic(Event)Message.

Hope this helps.
Cheers,

Allard

Hi Allard,

No, did not do that. How would I set this?

Thanks,

Danny

Hi Danny,

while diving into this, I can’t seem to find the place either. It’s been a while since I have configured Quartz for a project (still 1.x, at the time).
It seems that Spring’s SchedulerFactoryBean does some “magic” to get a classloader configured.

Axon uses the JobDataBinder to attach the event in the Job. By default, Quartz uses Java Serialization to serialize this JobDataMap. An alternative could be to serialize the message first, and set the serialized data on the JobDataMap instead, preventing the need for Quartz to (de)serialize classes using Java Serialization.
Anyway, it seems there is a slight misconfiguration in your Quartz setup, here, as it’s unable to load a class that seems to be around.

Hope this helps.
Cheers,

Allard