diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/JobLauncherApplicationRunner.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/JobLauncherApplicationRunner.java index c8fd079f235..bc2e129f2e3 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/JobLauncherApplicationRunner.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/batch/JobLauncherApplicationRunner.java @@ -40,7 +40,6 @@ import org.springframework.batch.core.converter.DefaultJobParametersConverter; import org.springframework.batch.core.converter.JobParametersConverter; import org.springframework.batch.core.explore.JobExplorer; import org.springframework.batch.core.launch.JobLauncher; -import org.springframework.batch.core.launch.NoSuchJobException; import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException; import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException; import org.springframework.batch.core.repository.JobRepository; @@ -65,6 +64,7 @@ import org.springframework.util.StringUtils; * @author Jean-Pierre Bergamin * @author Mahmoud Ben Hassine * @author Stephane Nicoll + * @author Akshay Dubey * @since 2.3.0 */ public class JobLauncherApplicationRunner @@ -116,6 +116,11 @@ public class JobLauncherApplicationRunner if (this.jobs.size() > 1 && !StringUtils.hasText(this.jobName)) { throw new IllegalArgumentException("Job name must be specified in case of multiple jobs"); } + if (StringUtils.hasText(this.jobName)) { + if (!isLocalJob(this.jobName) && !isRegisteredJob(this.jobName)) { + throw new IllegalArgumentException("No job found with name '" + this.jobName + "'"); + } + } } @Deprecated(since = "3.0.10", forRemoval = true) @@ -173,6 +178,14 @@ public class JobLauncherApplicationRunner executeRegisteredJobs(jobParameters); } + private boolean isLocalJob(String jobName) { + return this.jobs.stream().anyMatch((job) -> job.getName().equals(jobName)); + } + + private boolean isRegisteredJob(String jobName) { + return this.jobRegistry != null && this.jobRegistry.getJobNames().contains(jobName); + } + private void executeLocalJobs(JobParameters jobParameters) throws JobExecutionException { for (Job job : this.jobs) { if (StringUtils.hasText(this.jobName)) { @@ -187,14 +200,9 @@ public class JobLauncherApplicationRunner private void executeRegisteredJobs(JobParameters jobParameters) throws JobExecutionException { if (this.jobRegistry != null && StringUtils.hasText(this.jobName)) { - try { + if (!isLocalJob(this.jobName)) { Job job = this.jobRegistry.getJob(this.jobName); - if (!this.jobs.contains(job)) { - execute(job, jobParameters); - } - } - catch (NoSuchJobException ex) { - logger.debug(LogMessage.format("No job found in registry for job name: %s", this.jobName)); + execute(job, jobParameters); } } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfigurationTests.java index 60e8c7d5dca..6731d59f3ff 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/batch/BatchAutoConfigurationTests.java @@ -16,6 +16,7 @@ package org.springframework.boot.autoconfigure.batch; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -80,6 +81,8 @@ import org.springframework.transaction.PlatformTransactionManager; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; /** @@ -400,6 +403,53 @@ class BatchAutoConfigurationTests { .hasBean("customInitializer")); } + @Test + void whenTheUserDefinesAJobNameAsJobInstanceValidates() { + JobLauncherApplicationRunner runner = createInstance("another"); + runner.setJobs(Collections.singletonList(mockJob("test"))); + runner.setJobName("test"); + runner.afterPropertiesSet(); + } + + @Test + void whenTheUserDefinesAJobNameAsRegisteredJobValidates() { + JobLauncherApplicationRunner runner = createInstance("test"); + runner.setJobName("test"); + runner.afterPropertiesSet(); + } + + @Test + void whenTheUserDefinesAJobNameThatDoesNotExistWithJobInstancesFailsFast() { + JobLauncherApplicationRunner runner = createInstance(); + runner.setJobs(Arrays.asList(mockJob("one"), mockJob("two"))); + runner.setJobName("three"); + assertThatIllegalArgumentException().isThrownBy(runner::afterPropertiesSet) + .withMessage("No job found with name 'three'"); + } + + @Test + void whenTheUserDefinesAJobNameThatDoesNotExistWithRegisteredJobFailsFast() { + JobLauncherApplicationRunner runner = createInstance("one", "two"); + runner.setJobName("three"); + assertThatIllegalArgumentException().isThrownBy(runner::afterPropertiesSet) + .withMessage("No job found with name 'three'"); + } + + private JobLauncherApplicationRunner createInstance(String... registeredJobNames) { + JobLauncherApplicationRunner runner = new JobLauncherApplicationRunner(mock(JobLauncher.class), + mock(JobExplorer.class), mock(JobRepository.class)); + JobRegistry jobRegistry = mock(JobRegistry.class); + given(jobRegistry.getJobNames()).willReturn(Arrays.asList(registeredJobNames)); + runner.setJobRegistry(jobRegistry); + return runner; + } + + private Job mockJob(String name) { + Job job = mock(Job.class); + given(job.getName()).willReturn(name); + return job; + } + @Configuration(proxyBeanMethods = false) protected static class BatchDataSourceConfiguration {