spring-projects / spring-projects/spring-batch
NullPointerException in proxied job [BATCH-2860]
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 3k
- Forks
- 2.5k
- Avg merge
- 6d 53m
- Merged PRs (30d)
- 3
Description
Igor Shcherbak opened BATCH-2860 and commented
Input data:
- Job configuration is made of "batch:job" xml element with listeners and steps, that resulted in FlowJob created by Spring behind the scenes.
- Around aspect exists with pointcut:
@Around(value = "execution(* org.springframework.batch.core.Job.execute(..)) && args(jobExecution)")
Goal of aspect is just to track job execution.
- Job lunched using custom job launcher with injected org.springframework.batch.core.launch.support.SimpleJobLauncher and org.springframework.batch.core.Job in it
Actual result - NullPointerException in AbstractJob:
java.lang.NullPointerException: nulljava.lang.NullPointerException: null at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:309) [spring-batch-core-4.2.0.RELEASE.jar:4.2.0.RELEASE] at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:147) [spring-batch-core-4.2.0.RELEASE.jar:4.2.0.RELEASE] at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50) [spring-core-5.2.0.RELEASE.jar:5.2.0.RELEASE] at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:140) [spring-batch-core-4.2.0.RELEASE.jar:4.2.0.RELEASE]
Notes:
Job injected to custom launcher proxied: !image-2019-11-25-14-09-45-183.png!
As a result all fields are null(listener, jobRepository etc), when job is launched - proxy invoke underlying AbstractJob, but because of AbstractJob access those fields directly but not using getters - null pointer occurs. Without aspect, job bean injected to launcher so no issues when job invoked.
Possible fix - access fields(like jobRepository and other) in AbstractJob using getters, so proxy call real getters and return non null value
Workaround: during custom launcher initialization prepare proxied job injected to it:
public void afterPropertiesSet() throws Exception {
if (AopUtils.isCglibProxy(job)) {
// Copy required fields
setTargetObjectFieldToProxy("jobRepository");
setTargetObjectFieldToProxy("jobParametersValidator");
setTargetObjectFieldToProxy("listener");
}
}
private void setTargetObjectFieldToProxy(String fieldName) throws Exception {
// Get and initialize field
Field field = ReflectionUtils.findField(FlowJob.class, fieldName);
ReflectionUtils.makeAccessible(field);
// Get wrapped job bean
Object target = ((Advised) job).getTargetSource().getTarget();
// Get wrapped job bean field value
Object fieldValue = ReflectionUtils.getField(field, target);
// Set value to job wrapper
ReflectionUtils.setField(field, job, fieldValue);
}
Affects: 4.2.0
Attachments:
- image-2019-11-25-14-09-45-183.png (45.52 kB)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at AbstractJob.execute, especially AbstractJob.java:309, and trace how a proxied FlowJob is invoked through SimpleJobLauncher. Reproduce the XML batch:job with listeners and steps plus the around aspect described in the issue; done means launching the proxied job no longer raises the reported NullPointerException.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, spring
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100