title: How to rename job class for persistent Quartz Jobs?
body: <p>I have a test quartz job like this one.</p>
  
  <pre><code>package com.example.spring.quartz.basic;
  
  import org.quartz.Job;
  import org.quartz.JobDataMap;
  import org.quartz.JobExecutionContext;
  import org.quartz.JobExecutionException;
  
  public class ExampleJob implements Job
  {
      @Override
      public void execute(JobExecutionContext context) throws JobExecutionException
      {
          JobDataMap map = context.getMergedJobDataMap();
          String timeout = (String)map.get("timeout");
  
          System.out.println("ExampleJob.execute() " + timeout);
      }
  }
  </code></pre>
  
  <p>This job is persistent so it is written to the database, and it seems that Quartz writes the full qualified job class name <code>com.example.spring.quartz.basic.ExampleJob</code> to the database.</p>
  
  <p>So if refactor rename the <code>ExampleJob</code> to <code>ExampleJob2</code> I end up with the exception below because quartz looks for ExampleJob and gets a class not found exception. </p>
  
  <p><strong>Question: Is there some trick, or pattern I can use to be able to safely rename my job classes 
  without causing existing job definitions to break?</strong> </p>
  
  <pre><code>Exception in thread "main" org.springframework.context.ApplicationContextException: Failed to start bean 'quartzScheduler'; nested exception is org.springframework.scheduling.SchedulingException: Could not start Quartz Scheduler; nested exception is org.quartz.SchedulerConfigException: Failure occured during job recovery. [See nested exception: org.quartz.JobPersistenceException: Couldn't retrieve trigger: com.example.spring.quartz.basic.ExampleJob [See nested exception: java.lang.ClassNotFoundException: com.example.spring.quartz.basic.ExampleJob]]
      at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:170)
      at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:51)
      at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:339)
      at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:143)
      at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:108)
      at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:945)
      at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
      at org.springframework.context.support.ClassPathXmlApplicationContext.&lt;init&gt;(ClassPathXmlApplicationContext.java:139)
      at org.springframework.context.support.ClassPathXmlApplicationContext.&lt;init&gt;(ClassPathXmlApplicationContext.java:83)
      at com.example.spring.quartz.transactional.QuartzExampleJobMain.main(QuartzExampleJobMain.java:16)
  Caused by: org.springframework.scheduling.SchedulingException: Could not start Quartz Scheduler; nested exception is org.quartz.SchedulerConfigException: Failure occured during job recovery. [See nested exception: org.quartz.JobPersistenceException: Couldn't retrieve trigger: com.example.spring.quartz.basic.ExampleJob [See nested exception: java.lang.ClassNotFoundException: com.example.spring.quartz.basic.ExampleJob]]
      at org.springframework.scheduling.quartz.SchedulerFactoryBean.start(SchedulerFactoryBean.java:715)
      at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:167)
      ... 9 more
  Caused by: org.quartz.SchedulerConfigException: Failure occured during job recovery. [See nested exception: org.quartz.JobPersistenceException: Couldn't retrieve trigger: com.example.spring.quartz.basic.ExampleJob [See nested exception: java.lang.ClassNotFoundException: com.example.spring.quartz.basic.ExampleJob]]
      at org.quartz.impl.jdbcjobstore.JobStoreSupport.schedulerStarted(JobStoreSupport.java:683)
      at org.quartz.core.QuartzScheduler.start(QuartzScheduler.java:526)
      at org.quartz.impl.StdScheduler.start(StdScheduler.java:143)
      at org.springframework.scheduling.quartz.SchedulerFactoryBean.startScheduler(SchedulerFactoryBean.java:649)
      at org.springframework.scheduling.quartz.SchedulerFactoryBean.start(SchedulerFactoryBean.java:712)
      ... 10 more
  Caused by: org.quartz.JobPersistenceException: Couldn't retrieve trigger: com.example.spring.quartz.basic.ExampleJob [See nested exception: java.lang.ClassNotFoundException: com.example.spring.quartz.basic.ExampleJob]
      at org.quartz.impl.jdbcjobstore.JobStoreSupport.retrieveTrigger(JobStoreSupport.java:1524)
      at org.quartz.impl.jdbcjobstore.JobStoreSupport.recoverMisfiredJobs(JobStoreSupport.java:968)
      at org.quartz.impl.jdbcjobstore.JobStoreSupport.recoverJobs(JobStoreSupport.java:855)
      at org.quartz.impl.jdbcjobstore.JobStoreSupport$1.execute(JobStoreSupport.java:827)
      at org.quartz.impl.jdbcjobstore.JobStoreSupport$46.execute(JobStoreSupport.java:3764)
      at org.quartz.impl.jdbcjobstore.JobStoreSupport.executeInNonManagedTXLock(JobStoreSupport.java:3798)
      at org.quartz.impl.jdbcjobstore.JobStoreSupport.executeInNonManagedTXLock(JobStoreSupport.java:3760)
      at org.quartz.impl.jdbcjobstore.JobStoreSupport.recoverJobs(JobStoreSupport.java:823)
      at org.quartz.impl.jdbcjobstore.JobStoreSupport.schedulerStarted(JobStoreSupport.java:681)
      ... 14 more
  Caused by: java.lang.ClassNotFoundException: com.example.spring.quartz.basic.ExampleJob
      at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
      at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
      at java.security.AccessController.doPrivileged(Native Method)
      at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
      at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
      at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
      at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
      at java.lang.Class.forName0(Native Method)
      at java.lang.Class.forName(Class.java:270)
      at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:623)
      at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1610)
      at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1515)
      at java.io.ObjectInputStream.readClass(ObjectInputStream.java:1481)
      at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1331)
      at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1989)
      at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1913)
      at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1796)
      at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1348)
      at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370)
      at java.util.HashMap.readObject(HashMap.java:1155)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:606)
      at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1017)
      at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1891)
      at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1796)
      at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1348)
      at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1989)
      at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1913)
      at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1796)
      at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1348)
      at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370)
      at org.quartz.impl.jdbcjobstore.PostgreSQLDelegate.getObjectFromBlob(PostgreSQLDelegate.java:103)
      at org.quartz.impl.jdbcjobstore.StdJDBCDelegate.selectTrigger(StdJDBCDelegate.java:1764)
      at org.quartz.impl.jdbcjobstore.JobStoreSupport.retrieveTrigger(JobStoreSupport.java:1520)
      ... 22 more
  </code></pre>