7

I have a spring boot project that I want to use quartz with to run certain jobs at certain times. I have this class layout:

abstract public class AbstractFoo { protected final FooB fooB; public AbstractFoo(FooB fooB) { this.fooB = fooB; } } @Service public class SomeJob extends AbstractFoo implements Job { public SomeJob(FooB fooB) { super(fooB); } @Override public void execute(final JobExecutionContext context) throws JobExecutionException { //do stuff } } 

However, when I run this job I get the following error:

2017-12-06 14:18:01,383 ERROR --- [quartz-jobs] org.quartz.core.ErrorLogger : An error occured instantiating job to be executed. job= 'jobGroup.someJob' org.quartz.SchedulerException: Job instantiation failed at org.springframework.scheduling.quartz.AdaptableJobFactory.newJob(AdaptableJobFactory.java:45) at org.quartz.core.JobRunShell.initialize(JobRunShell.java:127) at org.quartz.core.QuartzSchedulerThread.run(QuartzSchedulerThread.java:375) Caused by: java.lang.InstantiationException: com.jobs.SomeJob at java.lang.Class.newInstance(Class.java:427) at org.springframework.scheduling.quartz.AdaptableJobFactory.createJobInstance(AdaptableJobFactory.java:58) at org.springframework.scheduling.quartz.SpringBeanJobFactory.createJobInstance(SpringBeanJobFactory.java:74) at com.config.AutowiringSpringBeanJobFactory.createJobInstance(AutowiringSpringBeanJobFactory.java:27) at org.springframework.scheduling.quartz.AdaptableJobFactory.newJob(AdaptableJobFactory.java:41) ... 2 common frames omitted Caused by: java.lang.NoSuchMethodException: com.jobs.SomeJob.<init>() at java.lang.Class.getConstructor0(Class.java:3082) at java.lang.Class.newInstance(Class.java:412) ... 6 common frames omitted 

I already have an autowire factory like so:

public final class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware { private transient AutowireCapableBeanFactory beanFactory; @Override public void setApplicationContext(final ApplicationContext context) { beanFactory = context.getAutowireCapableBeanFactory(); } @Override protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception { final Object job = super.createJobInstance(bundle); beanFactory.autowireBean(job); return job; } } 

And here's my quartz config:

@Configuration public class QuartzConfig { @Autowired private DataSource dataSource; @Autowired private PlatformTransactionManager transactionManager; @Autowired private ApplicationContext applicationContext; @Bean public SchedulerFactoryBean quartzScheduler() { SchedulerFactoryBean quartzScheduler = new SchedulerFactoryBean(); quartzScheduler.setDataSource(dataSource); quartzScheduler.setTransactionManager(transactionManager); quartzScheduler.setOverwriteExistingJobs(true); quartzScheduler.setSchedulerName("quartz-jobs"); AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory(); jobFactory.setApplicationContext(applicationContext); quartzScheduler.setJobFactory(jobFactory); quartzScheduler.setQuartzProperties(quartzProperties()); Trigger[] triggers = {someJobTrigger().getObject(); quartzScheduler.setTriggers(triggers); return quartzScheduler; } @Bean public CronTriggerFactoryBean someJobTrigger() { CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean(); cronTriggerFactoryBean.setJobDetail(someJob().getObject()); cronTriggerFactoryBean.setCronExpression(cronExp); cronTriggerFactoryBean.setGroup(someGroup); return cronTriggerFactoryBean; } @Bean public JobDetailFactoryBean someJob() { JobDetailFactoryBean jobDetailFactory = new JobDetailFactoryBean(); jobDetailFactory.setJobClass(SomeJob.class); jobDetailFactory.setGroup(someGroup); jobDetailFactory.setDurability(true); return jobDetailFactory; } @Bean public Properties quartzProperties() { PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean(); propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties")); Properties properties = null; try { propertiesFactoryBean.afterPropertiesSet(); properties = propertiesFactoryBean.getObject(); } catch (IOException e) { } return properties; } } 

How do I get Quartz to wire in the appropriate dependencies through the constructor?

2
  • Also make sure you are using spring-3.2.1 and quartz-2.1.6. If not post which version you are using of quartz/spring Commented Dec 6, 2017 at 20:45
  • @RobertI using quartz-2.2, spring-boot-1.5.7 and spring-4.3.4 Commented Dec 6, 2017 at 21:28

3 Answers 3

13

As stated in docs:

One of the ramifications of this behavior is the fact that jobs must have a no-argument constructor (when using the default JobFactory implementation).

You essentially using default JobFactory with autowiring capability added. What I found from my personal tests is that autowiring will not work with constructor injection. Also, don't mark your job with Spring annotations (Component, Service, e.c.t) as it has no effect.

To solve your problem, refactor your job to have default constructor and autowire dependencies with field injection (maybe setter injection will work too).

abstract public class AbstractFoo { @Autowired protected FooB fooB; } public class SomeJob extends AbstractFoo implements Job { @Override public void execute(final JobExecutionContext context) throws JobExecutionException { //do stuff } } 
Sign up to request clarification or add additional context in comments.

3 Comments

this doesn't work because I get the error: Cannot reference foo before supertype constructor has been called
I don't want to touch the base class as it affect many other classes
@Richard, you can pass in null which is ugly, change the parent class, or move the logic out of the job, and just delegate to some field-injected bean that calls your fooB
1

I just posted an answer here with just normal quartz with autowiring capability. However, please note that you need to have a no-args constructor(Use both no-args and arg constructor in your case). Quartz uses class name to instantiate instance and so, your constructor with argument wont work.

If you still are working on the same problem, try my approach where you can auto wire the required dependency instead of going via super(foo);

https://stackoverflow.com/a/49316580/2931410

Comments

0

This problem occures when class not contains default constructor.

Example : YourJob extends QuartzJobBean then class should contains default constructor. Add @Component adnotation and @NoArgsConstructor if you use lombok. Other required beans should be autowired to this class by @Autowired

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.