Skip to content

Commit 854c162

Browse files
committed
Polish "Fail fast if job name does not exist"
See gh-36060
1 parent c38cd74 commit 854c162

File tree

2 files changed

+62
-22
lines changed

2 files changed

+62
-22
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/JobLauncherApplicationRunner.java

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@
2424
import java.util.Map;
2525
import java.util.Properties;
2626

27-
import javax.annotation.PostConstruct;
28-
2927
import org.apache.commons.logging.Log;
3028
import org.apache.commons.logging.LogFactory;
3129

@@ -43,11 +41,11 @@
4341
import org.springframework.batch.core.explore.JobExplorer;
4442
import org.springframework.batch.core.launch.JobLauncher;
4543
import org.springframework.batch.core.launch.JobParametersNotFoundException;
46-
import org.springframework.batch.core.launch.NoSuchJobException;
4744
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
4845
import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
4946
import org.springframework.batch.core.repository.JobRepository;
5047
import org.springframework.batch.core.repository.JobRestartException;
48+
import org.springframework.beans.factory.InitializingBean;
5149
import org.springframework.beans.factory.annotation.Autowired;
5250
import org.springframework.boot.ApplicationArguments;
5351
import org.springframework.boot.ApplicationRunner;
@@ -71,7 +69,8 @@
7169
* @author Akshay Dubey
7270
* @since 2.3.0
7371
*/
74-
public class JobLauncherApplicationRunner implements ApplicationRunner, Ordered, ApplicationEventPublisherAware {
72+
public class JobLauncherApplicationRunner
73+
implements ApplicationRunner, InitializingBean, Ordered, ApplicationEventPublisherAware {
7574

7675
/**
7776
* The default order for the command line runner.
@@ -114,15 +113,14 @@ public JobLauncherApplicationRunner(JobLauncher jobLauncher, JobExplorer jobExpl
114113
this.jobRepository = jobRepository;
115114
}
116115

117-
@PostConstruct
118-
public void validate() {
116+
@Override
117+
public void afterPropertiesSet() {
119118
if (StringUtils.hasText(this.jobNames)) {
120-
String[] jobsToRun = this.jobNames.split(",");
121-
for(String jobName: jobsToRun) {
119+
for (String jobName : jobsToRun()) {
122120
if (!isLocalJob(jobName) && !isRegisteredJob(jobName)) {
123-
throw new IllegalArgumentException("No job instances were found for job name [" + jobName + "]");
121+
throw new IllegalArgumentException("No job found with name '" + jobName + "'");
124122
}
125-
}
123+
}
126124
}
127125
}
128126

@@ -187,7 +185,7 @@ private boolean isRegisteredJob(String jobName) {
187185
private void executeLocalJobs(JobParameters jobParameters) throws JobExecutionException {
188186
for (Job job : this.jobs) {
189187
if (StringUtils.hasText(this.jobNames)) {
190-
String[] jobsToRun = this.jobNames.split(",");
188+
String[] jobsToRun = jobsToRun();
191189
if (!PatternMatchUtils.simpleMatch(jobsToRun, job.getName())) {
192190
logger.debug(LogMessage.format("Skipped job: %s", job.getName()));
193191
continue;
@@ -199,9 +197,9 @@ private void executeLocalJobs(JobParameters jobParameters) throws JobExecutionEx
199197

200198
private void executeRegisteredJobs(JobParameters jobParameters) throws JobExecutionException {
201199
if (this.jobRegistry != null && StringUtils.hasText(this.jobNames)) {
202-
String[] jobsToRun = this.jobNames.split(",");
200+
String[] jobsToRun = jobsToRun();
203201
for (String jobName : jobsToRun) {
204-
if(isRegisteredJob(jobName) && !isLocalJob(jobName)) {
202+
if (!isLocalJob(jobName)) {
205203
Job job = this.jobRegistry.getJob(jobName);
206204
execute(job, jobParameters);
207205
}
@@ -263,4 +261,8 @@ private JobParameters merge(JobParameters parameters, JobParameters additionals)
263261
return new JobParameters(merged);
264262
}
265263

264+
private String[] jobsToRun() {
265+
return this.jobNames.split(",");
266+
}
267+
266268
}

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfigurationTests.java

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.boot.autoconfigure.batch;
1818

19+
import java.util.Arrays;
1920
import java.util.Collection;
2021
import java.util.Collections;
2122

@@ -71,6 +72,8 @@
7172

7273
import static org.assertj.core.api.Assertions.assertThat;
7374
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
75+
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
76+
import static org.mockito.BDDMockito.given;
7477
import static org.mockito.Mockito.mock;
7578

7679
/**
@@ -80,7 +83,6 @@
8083
* @author Stephane Nicoll
8184
* @author Vedran Pavic
8285
* @author Kazuki Shimizu
83-
* @author Akshay Dubey
8486
*/
8587
@ExtendWith(OutputCaptureExtension.class)
8688
class BatchAutoConfigurationTests {
@@ -376,14 +378,50 @@ void whenTheUserDefinesTheirOwnDatabaseInitializerThenTheAutoConfiguredBatchInit
376378
}
377379

378380
@Test
379-
void testNonConfiguredJobThrowsException() {
380-
this.contextRunner
381-
.withUserConfiguration(NamedJobConfigurationWithLocalJob.class, EmbeddedDataSourceConfiguration.class)
382-
.withPropertyValues("spring.batch.job.names:discreteLocalJob,nonConfiguredJob")
383-
.run((context) -> {
384-
assertThat(context).hasFailed().getFailure().getRootCause()
385-
.hasMessageContaining("nonConfiguredJob");
386-
});
381+
void whenTheUserDefinesAJobNameAsJobInstanceValidates() {
382+
JobLauncherApplicationRunner runner = createInstance("another");
383+
runner.setJobs(Collections.singletonList(mockJob("test")));
384+
runner.setJobNames("test");
385+
runner.afterPropertiesSet();
386+
}
387+
388+
@Test
389+
void whenTheUserDefinesAJobNameAsRegisteredJobValidates() {
390+
JobLauncherApplicationRunner runner = createInstance("test");
391+
runner.setJobNames("test");
392+
runner.afterPropertiesSet();
393+
}
394+
395+
@Test
396+
void whenTheUserDefinesAJobNameThatDoesNotExistWithJobInstancesFailsFast() {
397+
JobLauncherApplicationRunner runner = createInstance();
398+
runner.setJobs(Arrays.asList(mockJob("one"), mockJob("two")));
399+
runner.setJobNames("three");
400+
assertThatIllegalArgumentException().isThrownBy(runner::afterPropertiesSet)
401+
.withMessage("No job found with name 'three'");
402+
}
403+
404+
@Test
405+
void whenTheUserDefinesAJobNameThatDoesNotExistWithRegisteredJobFailsFast() {
406+
JobLauncherApplicationRunner runner = createInstance("one", "two");
407+
runner.setJobNames("three");
408+
assertThatIllegalArgumentException().isThrownBy(runner::afterPropertiesSet)
409+
.withMessage("No job found with name 'three'");
410+
}
411+
412+
private JobLauncherApplicationRunner createInstance(String... registeredJobNames) {
413+
JobLauncherApplicationRunner runner = new JobLauncherApplicationRunner(mock(JobLauncher.class),
414+
mock(JobExplorer.class), mock(JobRepository.class));
415+
JobRegistry jobRegistry = mock(JobRegistry.class);
416+
given(jobRegistry.getJobNames()).willReturn(Arrays.asList(registeredJobNames));
417+
runner.setJobRegistry(jobRegistry);
418+
return runner;
419+
}
420+
421+
private Job mockJob(String name) {
422+
Job job = mock(Job.class);
423+
given(job.getName()).willReturn(name);
424+
return job;
387425
}
388426

389427
@Configuration(proxyBeanMethods = false)

0 commit comments

Comments
 (0)