spring-projects / spring-projects/spring-batch

NullPointerException in proxied job [BATCH-2860]

Open
#754 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

status: waiting-for-triage type: bug
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:

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.