Question

I have configured a spring's method invoking job previously which is working fine. Now my requirement is to have this job as persistent which will run in a clustered environment. After configuring the quartz as clustered and persistence, application is throwing the following exception at deployment:

java.io.NotSerializableException: Unable to serialize JobDataMap for insertion into database because the value of property 'methodInvoker' is not serializable: org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean

I am using the following versions:

  • Spring version 3.1.4.RELEASE
  • Quartz version 2.1.7

Update: As per the documentation of MethodInvokingJobDetailFactoryBean:

JobDetails created via this FactoryBean are not serializable.

So, looking for some alternative approach to configure a persistent job in spring.

Was it helpful?

Solution

I have solved the problem by replacing MethodInvokingJobDetailFactoryBean with JobDetailFactoryBean. Configuration for the same is as follows:

<bean name="myJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
    <property name="jobClass" value="mypackage.MyJob" />
    <property name="group" value="MY_JOBS_GROUP" />
    <property name="durability" value="true" />
</bean>

However, to Autowire the spring managed beans in my job class mypackage.MyJob, I have added the following as first line in my execute method:

class MyJob implements Job {
    ...
    public void execute(final JobExecutionContext context) throws JobExecutionException {
        // Process @Autowired injection for the given target object, based on the current web application context. 
        SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
        ...
    }

}

Hope it it will help someone else facing the same issue.

OTHER TIPS

When you are using persistent quartz jobs, you should be setting the org.quartz.jobStore.useProperties property to true. That forces the job data to be saved as Strings instead of Java Serialized objects.

Doing so however may cause some problems with Spring, that are easily solvable.

Check these links for more details:

http://site.trimplement.com/using-spring-and-quartz-with-jobstore-properties/

http://forum.spring.io/forum/spring-projects/container/121806-quartz-error-ioexception

The other way to solve this problem is avoid using 'jobDataMap' property for 'JobDetailFactoryBean' bean. Instead, add the dependency (the bean containing method to run) in Scheudler with 'schedulerContextAsMap' property.

<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
     ... (other properties)...
     <property name="schedulerContextAsMap">
     <map>
       <entry key="executeProcessBean" value-ref="executeProcessBean" />
     </map>
  </property>
</bean>

Since, the documentation of schedulerContextAsMap in SchedulerFactoryBean mentions about the usage when you have Spring beans.

/**
     * Register objects in the Scheduler context via a given Map.
     * These objects will be available to any Job that runs in this Scheduler.
     * <p>Note: When using persistent Jobs whose JobDetail will be kept in the
     * database, do not put Spring-managed beans or an ApplicationContext
     * reference into the JobDataMap but rather into the SchedulerContext.
     * @param schedulerContextAsMap Map with String keys and any objects as
     * values (for example Spring-managed beans)
     * @see JobDetailFactoryBean#setJobDataAsMap
     */

just add implements Serializable

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top