Getting NULL POINTER With Dependency Injection in QuartzJobBean extended class - spring-boot

Iam using Quartz scheduler to run a Job, Here i am getting Null pointer Exception in the
QuartzJobBean extended class at Autowired Object i.e at DailyEmailsJob {testService.ts();}
please find the code below
This is the scheduler Class, Here i am calling DailyEmailsJob class
#Component
public interface EmailSchedulers {
void dailyEmailTrigger();
#Service
#Transactional
#Slf4j
public class Impl implements EmailSchedulers{
#Override
public void dailyEmailTrigger() {
JobDetail job = JobBuilder.newJob(DailyEmailsJob.class)
.withIdentity("DailyEmail", "group1")
.build();
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("DailyEmailTrigger", "group1")
.withSchedule(CronScheduleBuilder.cronSchedule("0 0 3 * * ?")) //At 03:00:00am every day
.build();
//schedule it
Scheduler scheduler;
try {
scheduler = new StdSchedulerFactory().getScheduler();
scheduler.start();
scheduler.scheduleJob(job, trigger);
} catch (SchedulerException e) {
e.printStackTrace();
log.info("erorrrrrrrrrrrrrrrrrr");
}
}
}
QuartzJobBean EXTENDED CLASS, Here at testService.ts(); i am getting Null pointer as shown in Error.
#Slf4j
#Component
public class DailyEmailsJob extends QuartzJobBean {
#Autowired
private TestService testService;
#Override
protected void executeInternal(JobExecutionContext arg0) throws JobExecutionException {
log.info("**************** DAILY SCHEDULER STARTED*****************");
testService.ts(); // Getting null pointer
log.info("**************** DAILY SCHEDULER ENDEND*****************");
}
}
This is the service class I am injecting at DailyEmailsJob class
#Component
public interface TestService {
void ts();
#Slf4j
#Service
public class Impl implements TestService{
#Override
public void ts() {
log.info("SERVICE WORKED");
}
}
}
This is the Error:
2018-09-23 03:00:00.040 INFO 6020 --- [eduler_Worker-1] DailyEmailsJob : **************** DAILY SCHEDULER STARTED*****************
2018-09-23 03:00:00.041 ERROR 6020 --- [eduler_Worker-1] org.quartz.core.JobRunShell : Job group1.DailyEmail threw an unhandled Exception:
java.lang.NullPointerException: null
at DailyEmailsJob.executeInternal(DailyEmailsJob.java:42) ~[classes/:na]
at org.springframework.scheduling.quartz.QuartzJobBean.execute(QuartzJobBean.java:75) ~[spring-context-support-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.quartz.core.JobRunShell.run(JobRunShell.java:202) ~[quartz-2.3.0.jar:na]
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) [quartz-2.3.0.jar:na]
2018-09-23 03:00:00.042 ERROR 6020 --- [eduler_Worker-1] org.quartz.core.ErrorLogger : Job (group1.DailyEmail threw an exception.
org.quartz.SchedulerException: Job threw an unhandled exception.
at org.quartz.core.JobRunShell.run(JobRunShell.java:213) ~[quartz-2.3.0.jar:na]
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) [quartz-2.3.0.jar:na]
Caused by: java.lang.NullPointerException: null
at DailyEmailsJob.executeInternal(DailyEmailsJob.java:42) ~[classes/:na]
at org.springframework.scheduling.quartz.QuartzJobBean.execute(QuartzJobBean.java:75) ~[spring-context-support-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.quartz.core.JobRunShell.run(JobRunShell.java:202) ~[quartz-2.3.0.jar:na]
... 1 common frames omitted

Add the following line to the start of the executeInternal method in DailyEmailsJob class:
#Override
public void executeInternal(final JobExecutionContext context) throws JobExecutionException {
// Adding this autowires everything as needed
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
...
}

Related

Spring Batch -#BeforeStep not getting invoked in ClassifierCompositeItemWriter

The method is not called with the #BeforeStep decorator that calls the ClassifierCompositeItemWriter, is there a workaround?
step
#Bean
public Step step2(ItemStreamReader <ValidateCandidateRentDto> itemValidateCandidateRentDtoReader,
ValidateCandidateRentProcess
itemValidateCandidateRentDtoProcess,ClassifierCompositeItemWriter<ValidateCandidateRentDto> classifierCompositeItemWriter) throws Exception {
return stepBuilderFactory.get("step2")
.<ValidateCandidateRentDto, ValidateCandidateRentDto>chunk(100)
.reader(itemValidateCandidateRentDtoReader)
.processor(itemValidateCandidateRentDtoProcess)
.writer(classifierCompositeItemWriter)
.build();
}
ClassifierCompositeItemWriter
#Bean
public ClassifierCompositeItemWriter<ValidateCandidateRentDto> classifierCompositeItemWriter(UpdateCandidateRentWriter itemUpdateCandidateRentDtoWriter, ValidateCandidateRentWriter itemValidateCandidateRentDtoWriter) throws Exception {
ClassifierCompositeItemWriter<ValidateCandidateRentDto> classifierCompositeItemWriter = new ClassifierCompositeItemWriter<>();
classifierCompositeItemWriter.setClassifier(new CandidateClassifier(itemUpdateCandidateRentDtoWriter,itemValidateCandidateRentDtoWriter));
return classifierCompositeItemWriter;
}
writer
public class ValidateCandidateRentWriter implements ItemWriter<ValidateCandidateRentDto> {
private static final Logger LOG = LoggerFactory.getLogger(ValidateCandidateRentWriter.class);
#Autowired
private CirCanRepRepository cirCanRepRepository;
private StepExecution stepExecution;
#BeforeStep
public void before(StepExecution stepExecution) {
this.stepExecution=stepExecution;
}
#Override
public void write(List<? extends ValidateCandidateRentDto> list) throws Exception {
this.stepExecution.getJobExecution().getExecutionContext().put("ValidateCandidatesRentDto",list);
}
}
log
java.lang.NullPointerException: null
at cl.ccla.reprogramacion.job.ValidateCandidateRentWriter.write(ValidateCandidateRentWriter.java:31) ~[classes/:?]
at org.springframework.batch.item.support.ClassifierCompositeItemWriter.write(ClassifierCompositeItemWriter.java:69) ~[spring-batch-infrastructure-4.2.4.RELEASE.jar:4.2.4.RELEASE]
Your ValidateCandidateRentWriter is not getting proxied as a StepExecutionListener. You need to declare it as a bean in your application context so that Spring (Batch) introspects the #BeforeStep method and creates a proxy for it.
Another option is to make this component implement StepExecutionListener and register it explicitly in the step definition.
Please check the documentation for more details about this feature.

Initilizing a constructor and inject a Repository bean of Jpa in Quartz [duplicate]

I have implemented Spring Quartz scheduler example using this link
I am having simple MyJobTwo.java component that has a method executeInternal() that is being called using CronTriggerFactoryBean.
This is my QuartzConfiguration.java
#Configuration
#ComponentScan("com.example")
public class QuartzConfiguration {
// we need to create a bean that will excuted by MethodInvokingJobDetailFactoryBean
// in this case we have myJobOne is the simple bean
#Bean
public MethodInvokingJobDetailFactoryBean methodInvokingJobDetailFactoryBean() {
MethodInvokingJobDetailFactoryBean obj = new MethodInvokingJobDetailFactoryBean();
obj.setTargetBeanName("myJobOne");
obj.setTargetMethod("myTask");
return obj;
}
// This trigger will schedule the job after 3 seconds and repeat after every 30 seconds for 3+1 times.
#Bean
public SimpleTriggerFactoryBean simpleTriggerFactoryBean(){
SimpleTriggerFactoryBean stFactory = new SimpleTriggerFactoryBean();
stFactory.setJobDetail(methodInvokingJobDetailFactoryBean().getObject());
stFactory.setStartDelay(3000);
stFactory.setRepeatInterval(30000);
stFactory.setRepeatCount(1);
return stFactory;
}
// We use it to configure complex job such as job scheduling using cron-expression
#Bean
public JobDetailFactoryBean jobDetailFactoryBean(){
JobDetailFactoryBean factory = new JobDetailFactoryBean();
factory.setJobClass(MyJobTwo.class);
// Map<String,Object> map = new HashMap<String,Object>();
// map.put("myJobOne", myJobOne);
// map.put(MyJobTwo.myJodOne, 1);
//factory.setJobDataAsMap(map);
//factory.setGroup("mygroup");
//factory.setName("myjob");
return factory;
}
// CronTriggerFactoryBean configures JobDetailFactoryBean
// We also configure start delay, trigger name, and cron-expression to schedule the job
#Bean
public CronTriggerFactoryBean cronTriggerFactoryBean(){
CronTriggerFactoryBean stFactory = new CronTriggerFactoryBean();
stFactory.setJobDetail(jobDetailFactoryBean().getObject());
stFactory.setStartDelay(3000);
//stFactory.setName("mytrigger");
//stFactory.setGroup("mygroup");
stFactory.setCronExpression("0 0/1 * 1/1 * ? *");
return stFactory;
}
// SchedulerFactoryBean use to register the triggers
// those registered triggers will be executed
#Bean
public SchedulerFactoryBean schedulerFactoryBean() {
SchedulerFactoryBean scheduler = new SchedulerFactoryBean();
scheduler.setTriggers(cronTriggerFactoryBean().getObject());
//scheduler.setTriggers(simpleTriggerFactoryBean().getObject());
return scheduler;
}
}
This is the bean that I am executing using CronTriggerFactoryBean.
MyJobTwo.java
#Component
public class MyJobTwo extends QuartzJobBean {
private SmtpMailSender smtpMailSender;
#Autowired
public MyJobTwo(MyJobOne myJobOne, SmtpMailSender smtpMailSender) {
super();
this.myJobOne = myJobOne;
this.smtpMailSender = smtpMailSender;
}
#Override
protected void executeInternal(JobExecutionContext ctx)
throws JobExecutionException {
System.out.println("this is the test");
myJobOne.myTask();
System.out.println("task is done");
}
}
Whenever I am trying to inject other beans and service I am getting these errors. Anyone having any idea what is causing these errors, what changes do I need to make?
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.example.job.MyJobTwo
at java.lang.Class.newInstance(Class.java:427)
at org.springframework.scheduling.quartz.AdaptableJobFactory.createJobInstance(AdaptableJobFactory.java:58)
at org.springframework.scheduling.quartz.AdaptableJobFactory.newJob(AdaptableJobFactory.java:41)
... 2 common frames omitted
Caused by: java.lang.NoSuchMethodException: com.example.job.MyJobTwo.<init>()
at java.lang.Class.getConstructor0(Class.java:3082)
at java.lang.Class.newInstance(Class.java:412)
... 4 common frames omitted
The default job factory implementation AdaptableJobFactory doesn't have autowiring capability.
To use dependency injection do following:
1.Create job factory
package com.concretepage.config;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;
public class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {
private transient AutowireCapableBeanFactory beanFactory;
public void setApplicationContext(final ApplicationContext context) {
beanFactory = context.getAutowireCapableBeanFactory();
}
#Override
public Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
final Object job = super.createJobInstance(bundle);
beanFactory.autowireBean(job); //the magic is done here
return job;
}
}
Implementation is found on http://codrspace.com/Khovansa/spring-quartz-with-a-database/
2.Update schedulerFactoryBean declaration in QuartzConfiguration:
#Bean
public SchedulerFactoryBean schedulerFactoryBean() {
SchedulerFactoryBean scheduler = new SchedulerFactoryBean();
scheduler.setTriggers(simpleTriggerFactoryBean().getObject(), cronTriggerFactoryBean().getObject());
scheduler.setJobFactory(jobFactory());
return scheduler;
}
#Bean
public JobFactory jobFactory() {
return new AutowiringSpringBeanJobFactory();
}
Use setter-based injection instead of constructor injection

ApplicationEventPublisher is not being autowired into Component

I have a Spring Boot app and #Component class which looks like:
#Component
public class CustomEvent {
#Autowired
ApplicationEventPublisher publisher;
#PreRemove
public void onItemDelete(Object entity) {
System.out.println(" =======PUBLISH====== " + entity);
publisher.publishEvent(new EntityDeleteEvent<>(entity));
}
}
When it goes to run above method the first line is printed with proper entity but the publisher.publishEvent line throws a NullPointerException. I suppose it that the ApplicationEventPublisher is not being #Autowired but couldn't find why. Other #Components which are in the app are found by #ComponentScanner.
Of course in my entity this CustomEvent is registered:
#Entity
#EntityListeners(
CustomEvent.class
)
#Data
#AllArgsConstructor
public class Item
The exact error which is thrown looks like:
2017-10-26 16:46:06.190 ERROR 10176 --- [io-8091-exec-10] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause
java.lang.NullPointerException: null
at com.inventory.events.CustomEvent.onItemDelete(CustomEvent.java:19)
Do you have any suggestion why publisher is null?
The initialisation of ApplicationEventPublisher doesn't happen OR will remain null, if you have created the CustomeEvent without the help of Bean (like CustomEvent event = new CustomEvent().
Instead, declare the CustomEvent as bean in your configuration (Spring) and get the CustomEvent using application context.
If CustomEvent is in the Spring's package scan, then I don't know.
But, there is an additional solution.
Create a class to instantiate spring managed class, but by ApplicationContext.
1 - Create the class below:
public class AppContextUtil implements ApplicationContextAware {
private static ApplicationContext context;
#Override
public void setApplicationContext(ApplicationContext appContext) throws BeansException {
context = appContext;
}
public static ApplicationContext getApplicationContext() {
return context;
}
public static <T> T getBean(Class<T> classe) {
return context.getBean(classe);
}
}
2 - Instance class as below:
public class CustomEvent {
private ApplicationEventPublisher publisher;
#PreRemove
public void onItemDelete(Object entity) {
System.out.println(" =======PUBLISH====== " + entity);
getApplicationEventPublisher().publishEvent(new EntityDeleteEvent<>(entity));
}
private ApplicationEventPublisher getApplicationEventPublisher() {
return AppContextUtil.getBean(ApplicationEventPublisher.class);
}
}

Using Spring Scheduler to return rows from DB throws Null pointer Exception

I am using Spring scheduling to schedule a task that performs some DB operation every hour. This throws a NullPointerException every time I try to call a function that triggers DB specific operations.
Configuration File :
#Configuration
#EnableWebMvc
#ComponentScan(basePackages="com.bt.rtddashboard")
/*#EnableJpaRepositories(basePackages = {
"com.bt.rtddashboard"
})*/
#EnableScheduling
#PropertySource("classpath:jdbc.properties")
public class RTDDashboardConfiguration extends WebMvcConfigurerAdapter {
#Resource
private Environment env;
#Bean(name = "dataSource", destroyMethod="close")
public DataSource getDataSource() {
//DB code
}
private Properties getHibernateProperties() {
//Hibernate code
}
#Bean(name = "sessionFactory")
#Scope("singleton")
public LocalSessionFactoryBean getSessionFactory() {
}
#Autowired
#Bean(name = "transactionManager")
public HibernateTransactionManager getHibernateTransactionManager(SessionFactory factory) {
;
}
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations("/").setCachePeriod(31556926);
}
#Scheduled(fixedRate=1000)
public void work() {
// task execution logic
System.out.println("Scheduled Task");
DashboardController controller=new DashboardController();
controller.performTask();
}
}
Dashboard Controller :
#RestController
public class DashboardController {
#Autowired
private InlineService service;
#RequestMapping(value="/rtd/getAllServers", method=RequestMethod.GET)
public ResponseEntity<List<ServerMonitor>> getAllServers(){
List<ServerMonitor> ilsList=new ArrayList<ServerMonitor>();
ResponseEntity<List<ServerMonitor>> response=null;
try{
ilsList=service.getAllServers();
response=new ResponseEntity<List<ServerMonitor>>(ilsList,HttpStatus.OK);
System.out.println("Scheduled Time");
}catch(Exception e){
}
return response;
}
public void performTask(){
System.out.println("Scheduled Task Starts in Contrroller");
List<IlsStats> ilsStats =new ArrayList<IlsStats>();
List<IlsStatsHistory> ilsStatsHisList=new ArrayList<IlsStatsHistory>();
try{
//get All the ILS Stats
ilsStats=service.getAllInlineStats();
System.out.println("No of rows to Copy : " + ilsStats.size());
ilsStatsHisList=formILSHistoryList(ilsStats);
int flag=service.insertInIlsStatsHistory(ilsStatsHisList);
//List<ServerMonitor> ilsList=service.getAllServers();
}catch(Exception e){
e.printStackTrace();
}
}
Here, ilsStats=service.getAllInlineStats(); throws NullPointerException.
Even though the rest webservice created on top of it is working fine.
Stack Trace :
Scheduled Task
Scheduled Task Starts in Contrroller
java.lang.NullPointerException
at com.bt.rtddashboard.controller.DashboardController.performTask(DashboardController.java:226)
at com.bt.rtddashboard.configuration.RTDDashboardConfiguration.work(RTDDashboardConfiguration.java:137)
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 org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:304)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:178)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
The same stack trace comes up every 1 sec now.
Creating an #Scheduled method in a configuration class is a very bad idea (imho). Next to that I also think that having a scheduler calling a controller method (a method tied to a web related component!) is generally a bad idea/design.
Nonetheless the problem is that you do new DashboardController(). That will obviously create a bean outside the scope of spring and will never be dependency injected. Instead inject the into the class and use that instance.
#Autowired
private DashboardController controller;
#Scheduled(fixedRate=1000)
public void work() {
controller.performTask();
}
Or even better just remove that method all together and simply place #Scheduled(fixedRate=1000) on the performTask method instead.

Injecting a bean at startup in Spring

I have a class RunBackgroundServices which runs some background services at startup. I need a new object BackgroundServices in it. So I am using WebApplicationContext to get the bean. But it's not working.
RunBackgroundServices.java
#WebListener
public class RunBackgroundServices implements ServletContextListener {
private ExecutorService executor;
public void contextInitialized(ServletContextEvent event) {
final WebApplicationContext springContext = WebApplicationContextUtils.getWebApplicationContext(event.getServletContext());
BackgroundServices backgroundServices = springContext.getBean(BackgroundServices.class);
executor = Executors.newSingleThreadExecutor();
executor.submit(backgroundServices); // Task should implement Runnable.
}
public void contextDestroyed(ServletContextEvent event) {
executor.shutdown();
}
}
BackgroundServices.java
#Service
public class BackgroundServices extends Thread {
#Autowired
ServerListener serverListener;
#Autowired
ClientListener clientListener;
private static final Logger logger = LoggerFactory
.getLogger(BackgroundServices.class);
public void run() {
logger.debug("BackgroundServices :: run");
try {
serverListener.start();
} catch (InterruptedException e) {
logger.error(e.getStackTrace().toString());
}
try {
clientListener.start();
} catch (InterruptedException e) {
logger.error(e.getStackTrace().toString());
}
}
}
I am getting the following error -
Exception sending context initialized event to listener instance of class com.emc.hl7.common.RunBackgroundServices
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.emc.hl7.common.BackgroundServices] is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:295)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1125)
at com.emc.hl7.common.RunBackgroundServices.contextInitialized(RunBackgroundServices.java:20)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4961)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5455)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:634)
at org.apache.catalina.startup.HostConfig.deployDescriptor(HostConfig.java:671)
at org.apache.catalina.startup.HostConfig$DeployDescriptor.run(HostConfig.java:1840)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
There is an easier way to perform bootstraping operations using Spring.
All you have to do is have Spring bean that implements ApplicationListener<ContextRefreshedEvent>
Your code would look like:
#Component
public class ContextStartupListener implements ApplicationListener<ContextRefreshedEvent> {
private final BackgroundServices backgroundServices;
private ExecutorService executor;
#Autowired
public ContextStartupListener(BackgroundServices backgroundServices) {
this.backgroundServices= backgroundServices;
}
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
if(!isRootApplicationContext(event)) {
return;
}
executor = Executors.newSingleThreadExecutor();
executor.submit(backgroundServices);
}
private boolean isRootApplicationContext(ContextRefreshedEvent event) {
return null == event.getApplicationContext().getParent();
}
}
Note the use of isRootApplicationContext. It is needed if you have multiple application contexts and do no want to run the bootstrapping operation on each one.
Using the above code you are bootstrapping using Spring's events, not the Servlet container's events.

Resources