This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new 3ae018ff09d CAMEL-22309: camel-spring-batch - Should auto wire job 
launcher and registry
3ae018ff09d is described below

commit 3ae018ff09d8f3f9035eb363451bef563f223e1d
Author: Claus Ibsen <[email protected]>
AuthorDate: Thu Jul 31 19:50:20 2025 +0200

    CAMEL-22309: camel-spring-batch - Should auto wire job launcher and registry
---
 .../camel/catalog/components/spring-batch.json     |   7 +-
 .../batch/SpringBatchComponentConfigurer.java      |   5 +
 .../camel/component/spring/batch/spring-batch.json |   7 +-
 .../spring/batch/SpringBatchComponent.java         |  19 +--
 .../spring/batch/SpringBatchConstants.java         |   5 +
 .../spring/batch/SpringBatchEndpoint.java          |  71 ++---------
 .../spring/batch/SpringBatchProducer.java          |   6 +-
 .../batch/SpringBatchEndpointDynamicTest.java      | 142 +++++++++++++++++++++
 .../spring/batch/SpringBatchEndpointTest.java      |  90 +------------
 .../spring/batch/SpringBatchJobLauncherIT.java     |   9 --
 .../batch/springBatchtestJobLauncherContext.xml    |   4 -
 .../ROOT/pages/camel-4x-upgrade-guide-4_14.adoc    |   4 +
 .../dsl/SpringBatchEndpointBuilderFactory.java     |  36 ++++++
 13 files changed, 222 insertions(+), 183 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/spring-batch.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/spring-batch.json
index 2955ce584fb..dc6e55c424e 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/spring-batch.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/spring-batch.json
@@ -24,11 +24,14 @@
     "remote": false
   },
   "componentProperties": {
-    "jobLauncher": { "index": 0, "kind": "property", "displayName": "Job 
Launcher", "group": "producer", "label": "", "required": false, "type": 
"object", "javaType": "org.springframework.batch.core.launch.JobLauncher", 
"deprecated": false, "autowired": false, "secret": false, "description": 
"Explicitly specifies a JobLauncher to be used." },
-    "jobRegistry": { "index": 1, "kind": "property", "displayName": "Job 
Registry", "group": "producer", "label": "", "required": false, "type": 
"object", "javaType": 
"org.springframework.batch.core.configuration.JobRegistry", "deprecated": 
false, "autowired": false, "secret": false, "description": "Explicitly 
specifies a JobRegistry to be used." },
+    "jobLauncher": { "index": 0, "kind": "property", "displayName": "Job 
Launcher", "group": "producer", "label": "", "required": false, "type": 
"object", "javaType": "org.springframework.batch.core.launch.JobLauncher", 
"deprecated": false, "autowired": true, "secret": false, "description": 
"Explicitly specifies a JobLauncher to be used." },
+    "jobRegistry": { "index": 1, "kind": "property", "displayName": "Job 
Registry", "group": "producer", "label": "", "required": false, "type": 
"object", "javaType": 
"org.springframework.batch.core.configuration.JobRegistry", "deprecated": 
false, "autowired": true, "secret": false, "description": "Explicitly specifies 
a JobRegistry to be used." },
     "lazyStartProducer": { "index": 2, "kind": "property", "displayName": 
"Lazy Start Producer", "group": "producer", "label": "producer", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": false, "description": 
"Whether the producer should be started lazy (on the first message). By 
starting lazy you can use this to allow CamelContext and routes to startup in 
situations where a producer may otherwise fail [...]
     "autowiredEnabled": { "index": 3, "kind": "property", "displayName": 
"Autowired Enabled", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": true, "description": 
"Whether autowiring is enabled. This is used for automatic autowiring options 
(the option must be marked as autowired) by looking up in the registry to find 
if there is a single instance of matching t [...]
   },
+  "headers": {
+    "CamelSpringBatchJobName": { "index": 0, "kind": "header", "displayName": 
"", "group": "producer", "label": "", "required": false, "javaType": "String", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The name of the Batch Job to use", "constantName": 
"org.apache.camel.component.spring.batch.SpringBatchConstants#JOB_NAME" }
+  },
   "properties": {
     "jobName": { "index": 0, "kind": "path", "displayName": "Job Name", 
"group": "producer", "label": "", "required": true, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The name of the Spring 
Batch job located in the registry." },
     "jobFromHeader": { "index": 1, "kind": "parameter", "displayName": "Job 
From Header", "group": "producer", "label": "", "required": false, "type": 
"boolean", "javaType": "boolean", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": false, "description": "Explicitly defines if 
the jobName should be taken from the headers instead of the URI." },
diff --git 
a/components/camel-spring-parent/camel-spring-batch/src/generated/java/org/apache/camel/component/spring/batch/SpringBatchComponentConfigurer.java
 
b/components/camel-spring-parent/camel-spring-batch/src/generated/java/org/apache/camel/component/spring/batch/SpringBatchComponentConfigurer.java
index 9fd44c4bcab..9e924b2962d 100644
--- 
a/components/camel-spring-parent/camel-spring-batch/src/generated/java/org/apache/camel/component/spring/batch/SpringBatchComponentConfigurer.java
+++ 
b/components/camel-spring-parent/camel-spring-batch/src/generated/java/org/apache/camel/component/spring/batch/SpringBatchComponentConfigurer.java
@@ -35,6 +35,11 @@ public class SpringBatchComponentConfigurer extends 
PropertyConfigurerSupport im
         }
     }
 
+    @Override
+    public String[] getAutowiredNames() {
+        return new String[]{"jobLauncher", "jobRegistry"};
+    }
+
     @Override
     public Class<?> getOptionType(String name, boolean ignoreCase) {
         switch (ignoreCase ? name.toLowerCase() : name) {
diff --git 
a/components/camel-spring-parent/camel-spring-batch/src/generated/resources/META-INF/org/apache/camel/component/spring/batch/spring-batch.json
 
b/components/camel-spring-parent/camel-spring-batch/src/generated/resources/META-INF/org/apache/camel/component/spring/batch/spring-batch.json
index 2955ce584fb..dc6e55c424e 100644
--- 
a/components/camel-spring-parent/camel-spring-batch/src/generated/resources/META-INF/org/apache/camel/component/spring/batch/spring-batch.json
+++ 
b/components/camel-spring-parent/camel-spring-batch/src/generated/resources/META-INF/org/apache/camel/component/spring/batch/spring-batch.json
@@ -24,11 +24,14 @@
     "remote": false
   },
   "componentProperties": {
-    "jobLauncher": { "index": 0, "kind": "property", "displayName": "Job 
Launcher", "group": "producer", "label": "", "required": false, "type": 
"object", "javaType": "org.springframework.batch.core.launch.JobLauncher", 
"deprecated": false, "autowired": false, "secret": false, "description": 
"Explicitly specifies a JobLauncher to be used." },
-    "jobRegistry": { "index": 1, "kind": "property", "displayName": "Job 
Registry", "group": "producer", "label": "", "required": false, "type": 
"object", "javaType": 
"org.springframework.batch.core.configuration.JobRegistry", "deprecated": 
false, "autowired": false, "secret": false, "description": "Explicitly 
specifies a JobRegistry to be used." },
+    "jobLauncher": { "index": 0, "kind": "property", "displayName": "Job 
Launcher", "group": "producer", "label": "", "required": false, "type": 
"object", "javaType": "org.springframework.batch.core.launch.JobLauncher", 
"deprecated": false, "autowired": true, "secret": false, "description": 
"Explicitly specifies a JobLauncher to be used." },
+    "jobRegistry": { "index": 1, "kind": "property", "displayName": "Job 
Registry", "group": "producer", "label": "", "required": false, "type": 
"object", "javaType": 
"org.springframework.batch.core.configuration.JobRegistry", "deprecated": 
false, "autowired": true, "secret": false, "description": "Explicitly specifies 
a JobRegistry to be used." },
     "lazyStartProducer": { "index": 2, "kind": "property", "displayName": 
"Lazy Start Producer", "group": "producer", "label": "producer", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": false, "description": 
"Whether the producer should be started lazy (on the first message). By 
starting lazy you can use this to allow CamelContext and routes to startup in 
situations where a producer may otherwise fail [...]
     "autowiredEnabled": { "index": 3, "kind": "property", "displayName": 
"Autowired Enabled", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": true, "description": 
"Whether autowiring is enabled. This is used for automatic autowiring options 
(the option must be marked as autowired) by looking up in the registry to find 
if there is a single instance of matching t [...]
   },
+  "headers": {
+    "CamelSpringBatchJobName": { "index": 0, "kind": "header", "displayName": 
"", "group": "producer", "label": "", "required": false, "javaType": "String", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The name of the Batch Job to use", "constantName": 
"org.apache.camel.component.spring.batch.SpringBatchConstants#JOB_NAME" }
+  },
   "properties": {
     "jobName": { "index": 0, "kind": "path", "displayName": "Job Name", 
"group": "producer", "label": "", "required": true, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The name of the Spring 
Batch job located in the registry." },
     "jobFromHeader": { "index": 1, "kind": "parameter", "displayName": "Job 
From Header", "group": "producer", "label": "", "required": false, "type": 
"boolean", "javaType": "boolean", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": false, "description": "Explicitly defines if 
the jobName should be taken from the headers instead of the URI." },
diff --git 
a/components/camel-spring-parent/camel-spring-batch/src/main/java/org/apache/camel/component/spring/batch/SpringBatchComponent.java
 
b/components/camel-spring-parent/camel-spring-batch/src/main/java/org/apache/camel/component/spring/batch/SpringBatchComponent.java
index 1a0c84022aa..edda605605c 100644
--- 
a/components/camel-spring-parent/camel-spring-batch/src/main/java/org/apache/camel/component/spring/batch/SpringBatchComponent.java
+++ 
b/components/camel-spring-parent/camel-spring-batch/src/main/java/org/apache/camel/component/spring/batch/SpringBatchComponent.java
@@ -28,14 +28,9 @@ import org.springframework.batch.core.launch.JobLauncher;
 @Component("spring-batch")
 public class SpringBatchComponent extends DefaultComponent {
 
-    private static final String DEFAULT_JOB_LAUNCHER_REF_NAME = "jobLauncher";
-
-    private JobLauncher defaultResolvedJobLauncher;
-    private Map<String, JobLauncher> allResolvedJobLaunchers;
-
-    @Metadata
+    @Metadata(autowired = true)
     private JobLauncher jobLauncher;
-    @Metadata
+    @Metadata(autowired = true)
     private JobRegistry jobRegistry;
 
     public SpringBatchComponent() {
@@ -44,8 +39,7 @@ public class SpringBatchComponent extends DefaultComponent {
     @Override
     protected Endpoint createEndpoint(String uri, String remaining, 
Map<String, Object> parameters) throws Exception {
         SpringBatchEndpoint endpoint = new SpringBatchEndpoint(
-                uri, this, jobLauncher, defaultResolvedJobLauncher,
-                allResolvedJobLaunchers, remaining, jobRegistry);
+                uri, this, jobLauncher, remaining, jobRegistry);
         setProperties(endpoint, parameters);
         return endpoint;
     }
@@ -53,9 +47,10 @@ public class SpringBatchComponent extends DefaultComponent {
     @Override
     protected void doInit() throws Exception {
         super.doInit();
-        defaultResolvedJobLauncher
-                = 
getCamelContext().getRegistry().lookupByNameAndType(DEFAULT_JOB_LAUNCHER_REF_NAME,
 JobLauncher.class);
-        allResolvedJobLaunchers = 
getCamelContext().getRegistry().findByTypeWithName(JobLauncher.class);
+        if (jobLauncher == null) {
+            jobLauncher = getCamelContext().getRegistry()
+                    
.lookupByNameAndType(SpringBatchConstants.DEFAULT_JOB_LAUNCHER_REF_NAME, 
JobLauncher.class);
+        }
     }
 
     public JobLauncher getJobLauncher() {
diff --git 
a/components/camel-spring-parent/camel-spring-batch/src/main/java/org/apache/camel/component/spring/batch/SpringBatchConstants.java
 
b/components/camel-spring-parent/camel-spring-batch/src/main/java/org/apache/camel/component/spring/batch/SpringBatchConstants.java
index 07e4e46a7e7..a3876601947 100644
--- 
a/components/camel-spring-parent/camel-spring-batch/src/main/java/org/apache/camel/component/spring/batch/SpringBatchConstants.java
+++ 
b/components/camel-spring-parent/camel-spring-batch/src/main/java/org/apache/camel/component/spring/batch/SpringBatchConstants.java
@@ -16,11 +16,16 @@
  */
 package org.apache.camel.component.spring.batch;
 
+import org.apache.camel.spi.Metadata;
+
 /**
  * Constants.
  */
 public final class SpringBatchConstants {
 
+    public static final String DEFAULT_JOB_LAUNCHER_REF_NAME = "jobLauncher";
+
+    @Metadata(description = "The name of the Batch Job to use", javaType = 
"String")
     public static final String JOB_NAME = "CamelSpringBatchJobName";
 
     private SpringBatchConstants() {
diff --git 
a/components/camel-spring-parent/camel-spring-batch/src/main/java/org/apache/camel/component/spring/batch/SpringBatchEndpoint.java
 
b/components/camel-spring-parent/camel-spring-batch/src/main/java/org/apache/camel/component/spring/batch/SpringBatchEndpoint.java
index 345e60f558f..34f54554fc4 100644
--- 
a/components/camel-spring-parent/camel-spring-batch/src/main/java/org/apache/camel/component/spring/batch/SpringBatchEndpoint.java
+++ 
b/components/camel-spring-parent/camel-spring-batch/src/main/java/org/apache/camel/component/spring/batch/SpringBatchEndpoint.java
@@ -16,8 +16,6 @@
  */
 package org.apache.camel.component.spring.batch;
 
-import java.util.Map;
-
 import org.apache.camel.Category;
 import org.apache.camel.Component;
 import org.apache.camel.Consumer;
@@ -37,40 +35,26 @@ import org.springframework.batch.core.launch.JobLauncher;
  * Send messages to Spring Batch for further processing.
  */
 @UriEndpoint(firstVersion = "2.10.0", scheme = "spring-batch", title = "Spring 
Batch", syntax = "spring-batch:jobName",
-             remote = false, producerOnly = true, category = { 
Category.WORKFLOW })
+             remote = false, producerOnly = true, headersClass = 
SpringBatchConstants.class, category = { Category.WORKFLOW })
 public class SpringBatchEndpoint extends DefaultEndpoint {
 
     @UriPath
     @Metadata(required = true)
     private String jobName;
-
     @UriParam
     private boolean jobFromHeader;
-
-    /**
-     * @deprecated will be removed in Camel 3.0 use jobLauncher instead
-     */
-    @Deprecated
-    private String jobLauncherRef;
-
     @UriParam
     private JobLauncher jobLauncher;
-
-    private JobLauncher defaultResolvedJobLauncher;
-    private Map<String, JobLauncher> allResolvedJobLaunchers;
-    private Job job;
-
     @UriParam
     private JobRegistry jobRegistry;
 
+    private Job job;
+
     public SpringBatchEndpoint(String endpointUri, Component component,
-                               JobLauncher jobLauncher, JobLauncher 
defaultResolvedJobLauncher,
-                               Map<String, JobLauncher> 
allResolvedJobLaunchers, String jobName,
-                               JobRegistry jobRegistry) {
+                               JobLauncher jobLauncher,
+                               String jobName, JobRegistry jobRegistry) {
         super(endpointUri, component);
         this.jobLauncher = jobLauncher;
-        this.defaultResolvedJobLauncher = defaultResolvedJobLauncher;
-        this.allResolvedJobLaunchers = allResolvedJobLaunchers;
         this.jobName = jobName;
         this.jobRegistry = jobRegistry;
     }
@@ -91,42 +75,20 @@ public class SpringBatchEndpoint extends DefaultEndpoint {
     }
 
     @Override
-    protected void doInit() throws Exception {
-        super.doInit();
+    protected void doStart() throws Exception {
+        super.doStart();
 
         if (jobLauncher == null) {
-            jobLauncher = resolveJobLauncher();
+            jobLauncher = 
CamelContextHelper.mandatoryFindSingleByType(getCamelContext(), 
JobLauncher.class);
         }
         if (job == null && jobName != null && !jobFromHeader) {
             if (jobRegistry != null) {
                 job = jobRegistry.getJob(jobName);
-            } else {
-                job = CamelContextHelper.mandatoryLookup(getCamelContext(), 
jobName, Job.class);
             }
-        }
-    }
-
-    private JobLauncher resolveJobLauncher() {
-        if (jobLauncherRef != null) {
-            JobLauncher jobLauncher = 
getCamelContext().getRegistry().lookupByNameAndType(jobLauncherRef, 
JobLauncher.class);
-            if (jobLauncher == null) {
-                throw new IllegalStateException(
-                        String.format("No JobLauncher named %s found in the 
registry.", jobLauncherRef));
+            if (job == null) {
+                job = CamelContextHelper.mandatoryLookup(getCamelContext(), 
jobName, Job.class);
             }
-            return jobLauncher;
-        }
-
-        if (defaultResolvedJobLauncher != null) {
-            return defaultResolvedJobLauncher;
         }
-
-        if (allResolvedJobLaunchers.size() == 1) {
-            return allResolvedJobLaunchers.values().iterator().next();
-        } else if (allResolvedJobLaunchers.size() > 1) {
-            throw new IllegalStateException("Expected single jobLauncher 
instance. Found: " + allResolvedJobLaunchers.size());
-        }
-
-        throw new IllegalStateException("Cannot find Spring Batch 
JobLauncher.");
     }
 
     public String getJobName() {
@@ -140,19 +102,6 @@ public class SpringBatchEndpoint extends DefaultEndpoint {
         this.jobName = jobName;
     }
 
-    @Deprecated
-    public String getJobLauncherRef() {
-        return jobLauncherRef;
-    }
-
-    /**
-     * Explicitly specifies a JobLauncher to be used looked up from the 
registry.
-     */
-    @Deprecated
-    public void setJobLauncherRef(String jobLauncherRef) {
-        this.jobLauncherRef = jobLauncherRef;
-    }
-
     public JobLauncher getJobLauncher() {
         return jobLauncher;
     }
diff --git 
a/components/camel-spring-parent/camel-spring-batch/src/main/java/org/apache/camel/component/spring/batch/SpringBatchProducer.java
 
b/components/camel-spring-parent/camel-spring-batch/src/main/java/org/apache/camel/component/spring/batch/SpringBatchProducer.java
index 9cab4e55894..1598269accd 100644
--- 
a/components/camel-spring-parent/camel-spring-batch/src/main/java/org/apache/camel/component/spring/batch/SpringBatchProducer.java
+++ 
b/components/camel-spring-parent/camel-spring-batch/src/main/java/org/apache/camel/component/spring/batch/SpringBatchProducer.java
@@ -40,9 +40,7 @@ public class SpringBatchProducer extends DefaultProducer {
     private static final Logger LOG = 
LoggerFactory.getLogger(SpringBatchProducer.class);
 
     private final JobLauncher jobLauncher;
-
     private final Job job;
-
     private final JobRegistry jobRegistry;
 
     public SpringBatchProducer(SpringBatchEndpoint endpoint, JobLauncher 
jobLauncher, Job job, JobRegistry jobRegistry) {
@@ -54,7 +52,6 @@ public class SpringBatchProducer extends DefaultProducer {
 
     @Override
     public void process(Exchange exchange) throws Exception {
-
         JobParameters jobParameters = 
prepareJobParameters(exchange.getIn().getHeaders());
         String messageJobName = 
jobParameters.getString(SpringBatchConstants.JOB_NAME);
 
@@ -63,7 +60,8 @@ public class SpringBatchProducer extends DefaultProducer {
         if (messageJobName != null) {
             if (jobRegistry != null) {
                 job2run = jobRegistry.getJob(messageJobName);
-            } else {
+            }
+            if (job2run == null) {
                 job2run = 
CamelContextHelper.mandatoryLookup(getEndpoint().getCamelContext(), 
messageJobName, Job.class);
             }
         }
diff --git 
a/components/camel-spring-parent/camel-spring-batch/src/test/java/org/apache/camel/component/spring/batch/SpringBatchEndpointDynamicTest.java
 
b/components/camel-spring-parent/camel-spring-batch/src/test/java/org/apache/camel/component/spring/batch/SpringBatchEndpointDynamicTest.java
new file mode 100644
index 00000000000..443c2310de5
--- /dev/null
+++ 
b/components/camel-spring-parent/camel-spring-batch/src/test/java/org/apache/camel/component/spring/batch/SpringBatchEndpointDynamicTest.java
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.spring.batch;
+
+import java.time.Instant;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.camel.EndpointInject;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.spi.Registry;
+import org.apache.camel.test.junit5.CamelTestSupport;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoSettings;
+import org.mockito.quality.Strictness;
+import org.springframework.batch.core.Job;
+import org.springframework.batch.core.configuration.JobRegistry;
+import org.springframework.batch.core.launch.JobLauncher;
+
+import static org.apache.camel.test.junit5.TestSupport.header;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@MockitoSettings(strictness = Strictness.LENIENT)
+public class SpringBatchEndpointDynamicTest extends CamelTestSupport {
+
+    // Fixtures
+    @Mock
+    JobLauncher jobLauncher;
+
+    @Mock
+    JobRegistry jobRegistry;
+
+    @Mock
+    Job dynamicMockjob;
+
+    // Camel fixtures
+    @EndpointInject("mock:test")
+    MockEndpoint mockEndpoint;
+
+    @EndpointInject("mock:error")
+    MockEndpoint errorEndpoint;
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                
from("direct:dynamic").to("spring-batch:fake?jobFromHeader=true").errorHandler(deadLetterChannel("mock:error"))
+                        .to("mock:test");
+                
from("direct:dynamicWithJobRegistry").to("spring-batch:fake?jobFromHeader=true&jobRegistry=#jobRegistry")
+                        
.errorHandler(deadLetterChannel("mock:error")).to("mock:test");
+            }
+        };
+    }
+
+    @Override
+    protected void bindToRegistry(Registry registry) {
+        registry.bind("jobLauncher", jobLauncher);
+        registry.bind("dynamicMockjob", dynamicMockjob);
+        registry.bind("jobRegistry", jobRegistry);
+    }
+
+    // Tests
+    @Test
+    public void dynamicJobFailsIfHeaderNotPressent() throws Exception {
+
+        mockEndpoint.expectedMessageCount(0);
+        errorEndpoint.expectedMessageCount(1);
+
+        //dynamic job should fail as header is not present and the job is 
dynamic
+        sendBody("direct:dyanmic?block=false", "Start the job, please.");
+        mockEndpoint.assertIsSatisfied();
+        mockEndpoint.assertIsSatisfied();
+    }
+
+    @Test
+    public void dynamicJobFailsIfHeaderWithInvalidJobName() throws Exception {
+
+        mockEndpoint.expectedMessageCount(0);
+        errorEndpoint.expectedMessageCount(1);
+
+        //dynamic job should fail as header is present but the job does not 
exist
+        
header(SpringBatchConstants.JOB_NAME).append("thisJobDoesNotExsistAtAll" + 
Date.from(Instant.now()));
+        sendBody("direct:dyanmic?block=false", "Start the job, please.");
+
+        mockEndpoint.assertIsSatisfied();
+        mockEndpoint.assertIsSatisfied();
+    }
+
+    @Test
+    public void dynamicJobWorksIfHeaderPressentWithValidJob() throws Exception 
{
+
+        mockEndpoint.expectedMessageCount(1);
+        errorEndpoint.expectedMessageCount(0);
+
+        final Map<String, Object> headers = new HashMap<>();
+        headers.put(SpringBatchConstants.JOB_NAME, "dynamicMockjob");
+
+        sendBody("direct:dynamic?block=false", "Start the job, please.", 
headers);
+
+        mockEndpoint.assertIsSatisfied();
+        errorEndpoint.assertIsSatisfied();
+    }
+
+    @Test
+    public void 
dynamicJobWorksIfHeaderPresentWithValidJobLocatedInJobRegistry() throws 
Exception {
+        mockEndpoint.expectedMessageCount(1);
+        errorEndpoint.expectedMessageCount(0);
+
+        Job mockJob = mock(Job.class);
+        
when(jobRegistry.getJob(eq("dyanmicMockJobFromJobRegistry"))).thenReturn(mockJob);
+
+        final Map<String, Object> headers = new HashMap<>();
+        headers.put(SpringBatchConstants.JOB_NAME, 
"dyanmicMockJobFromJobRegistry");
+        headers.put("jobRegistry", "#jobRegistry");
+
+        sendBody("direct:dynamicWithJobRegistry", "Start the job, please.", 
headers);
+
+        mockEndpoint.assertIsSatisfied();
+        errorEndpoint.assertIsSatisfied();
+    }
+
+}
diff --git 
a/components/camel-spring-parent/camel-spring-batch/src/test/java/org/apache/camel/component/spring/batch/SpringBatchEndpointTest.java
 
b/components/camel-spring-parent/camel-spring-batch/src/test/java/org/apache/camel/component/spring/batch/SpringBatchEndpointTest.java
index 52508a003bf..7b14d5b61d9 100644
--- 
a/components/camel-spring-parent/camel-spring-batch/src/test/java/org/apache/camel/component/spring/batch/SpringBatchEndpointTest.java
+++ 
b/components/camel-spring-parent/camel-spring-batch/src/test/java/org/apache/camel/component/spring/batch/SpringBatchEndpointTest.java
@@ -16,14 +16,10 @@
  */
 package org.apache.camel.component.spring.batch;
 
-import java.time.Instant;
 import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.EndpointInject;
-import org.apache.camel.FailedToCreateRouteException;
 import org.apache.camel.FailedToStartRouteException;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.mock.MockEndpoint;
@@ -43,7 +39,6 @@ import org.springframework.batch.core.JobParameters;
 import org.springframework.batch.core.configuration.JobRegistry;
 import org.springframework.batch.core.launch.JobLauncher;
 
-import static org.apache.camel.test.junit5.TestSupport.header;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertSame;
 import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -85,10 +80,6 @@ public class SpringBatchEndpointTest extends 
CamelTestSupport {
             @Override
             public void configure() throws Exception {
                 
from("direct:start").to("spring-batch:mockJob").to("mock:test");
-                
from("direct:dynamic").to("spring-batch:fake?jobFromHeader=true").errorHandler(deadLetterChannel("mock:error"))
-                        .to("mock:test");
-                
from("direct:dynamicWithJobRegistry").to("spring-batch:fake?jobFromHeader=true&jobRegistry=#jobRegistry")
-                        
.errorHandler(deadLetterChannel("mock:error")).to("mock:test");
             }
         };
     }
@@ -103,65 +94,6 @@ public class SpringBatchEndpointTest extends 
CamelTestSupport {
     }
 
     // Tests
-    @Test
-    public void dynamicJobFailsIfHeaderNotPressent() throws Exception {
-
-        mockEndpoint.expectedMessageCount(0);
-        errorEndpoint.expectedMessageCount(1);
-
-        //dynamic job should fail as header is not present and the job is 
dynamic
-        sendBody("direct:dyanmic?block=false", "Start the job, please.");
-        mockEndpoint.assertIsSatisfied();
-        mockEndpoint.assertIsSatisfied();
-    }
-
-    @Test
-    public void dynamicJobFailsIfHeaderWithInvalidJobName() throws Exception {
-
-        mockEndpoint.expectedMessageCount(0);
-        errorEndpoint.expectedMessageCount(1);
-
-        //dynamic job should fail as header is present but the job does not 
exist
-        
header(SpringBatchConstants.JOB_NAME).append("thisJobDoesNotExsistAtAll" + 
Date.from(Instant.now()));
-        sendBody("direct:dyanmic?block=false", "Start the job, please.");
-
-        mockEndpoint.assertIsSatisfied();
-        mockEndpoint.assertIsSatisfied();
-    }
-
-    @Test
-    public void dynamicJobWorksIfHeaderPressentWithValidJob() throws Exception 
{
-
-        mockEndpoint.expectedMessageCount(1);
-        errorEndpoint.expectedMessageCount(0);
-
-        final Map<String, Object> headers = new HashMap<>();
-        headers.put(SpringBatchConstants.JOB_NAME, "dynamicMockjob");
-
-        sendBody("direct:dynamic?block=false", "Start the job, please.", 
headers);
-
-        mockEndpoint.assertIsSatisfied();
-        errorEndpoint.assertIsSatisfied();
-    }
-
-    @Test
-    public void 
dynamicJobWorksIfHeaderPresentWithValidJobLocatedInJobRegistry() throws 
Exception {
-
-        mockEndpoint.expectedMessageCount(1);
-        errorEndpoint.expectedMessageCount(0);
-
-        Job mockJob = mock(Job.class);
-        
when(jobRegistry.getJob(eq("dyanmicMockJobFromJobRegistry"))).thenReturn(mockJob);
-
-        final Map<String, Object> headers = new HashMap<>();
-        headers.put(SpringBatchConstants.JOB_NAME, 
"dyanmicMockJobFromJobRegistry");
-        headers.put("jobRegistry", "#jobRegistry");
-
-        sendBody("direct:dynamicWithJobRegistry", "Start the job, please.", 
headers);
-
-        mockEndpoint.assertIsSatisfied();
-        errorEndpoint.assertIsSatisfied();
-    }
 
     @Test
     public void shouldInjectJobToEndpoint() throws IllegalAccessException {
@@ -305,27 +237,7 @@ public class SpringBatchEndpointTest extends 
CamelTestSupport {
         });
 
         // When
-        assertThrows(FailedToCreateRouteException.class,
-                () -> camelContext.start());
-    }
-
-    @Test
-    public void shouldFailWhenThereIsMoreThanOneJobLauncher() throws Exception 
{
-        // Given
-        SimpleRegistry registry = new SimpleRegistry();
-        registry.bind("mockJob", job);
-        registry.bind("launcher1", jobLauncher);
-        registry.bind("launcher2", jobLauncher);
-        CamelContext camelContext = new DefaultCamelContext(registry);
-        camelContext.addRoutes(new RouteBuilder() {
-            @Override
-            public void configure() throws Exception {
-                from("direct:start").to("spring-batch:mockJob");
-            }
-        });
-
-        // When
-        assertThrows(FailedToCreateRouteException.class,
+        assertThrows(FailedToStartRouteException.class,
                 () -> camelContext.start());
     }
 
diff --git 
a/components/camel-spring-parent/camel-spring-batch/src/test/java/org/apache/camel/component/spring/batch/SpringBatchJobLauncherIT.java
 
b/components/camel-spring-parent/camel-spring-batch/src/test/java/org/apache/camel/component/spring/batch/SpringBatchJobLauncherIT.java
index 6123e4bbf5a..d7a9a3687b9 100644
--- 
a/components/camel-spring-parent/camel-spring-batch/src/test/java/org/apache/camel/component/spring/batch/SpringBatchJobLauncherIT.java
+++ 
b/components/camel-spring-parent/camel-spring-batch/src/test/java/org/apache/camel/component/spring/batch/SpringBatchJobLauncherIT.java
@@ -53,15 +53,6 @@ public class SpringBatchJobLauncherIT extends 
CamelSpringTestSupport {
         outputEndpoint.assertIsSatisfied();
     }
 
-    @Test
-    public void testJobLauncherRef() throws InterruptedException {
-        outputEndpoint.expectedBodiesReceived("Echo foo", "Echo bar", "Echo 
baz");
-
-        template.sendBody("direct:start-jobLauncherRef", "Start batch!");
-
-        outputEndpoint.assertIsSatisfied();
-    }
-
     @Override
     protected AbstractApplicationContext createApplicationContext() {
         return new ClassPathXmlApplicationContext(
diff --git 
a/components/camel-spring-parent/camel-spring-batch/src/test/resources/org/apache/camel/component/spring/batch/springBatchtestJobLauncherContext.xml
 
b/components/camel-spring-parent/camel-spring-batch/src/test/resources/org/apache/camel/component/spring/batch/springBatchtestJobLauncherContext.xml
index ab19b1bb2cb..43bb137488a 100644
--- 
a/components/camel-spring-parent/camel-spring-batch/src/test/resources/org/apache/camel/component/spring/batch/springBatchtestJobLauncherContext.xml
+++ 
b/components/camel-spring-parent/camel-spring-batch/src/test/resources/org/apache/camel/component/spring/batch/springBatchtestJobLauncherContext.xml
@@ -42,10 +42,6 @@
     <!-- Camel infrastructure -->
 
     <camel:camelContext id="camel">
-        <camel:route>
-            <camel:from uri="direct:start-jobLauncherRef"/>
-            <camel:to uri="spring-batch:echoJob?jobLauncherRef=jobLauncher"/>
-        </camel:route>
         <camel:route>
             <camel:from uri="direct:start-jobLauncher"/>
             <camel:to uri="spring-batch:echoJob?jobLauncher=#jobLauncher"/>
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_14.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_14.adoc
index da0fb875900..1ce75daf702 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_14.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_14.adoc
@@ -88,3 +88,7 @@ The ids parameter for camel-weather has been defined as 
String instead of List<S
 
 The addresses, privateFor and Topics parameters for camel-web3j have been 
defined as String instead of List<String>. For the migration users will need 
to, eventually, define addresses, privateFor or topics  as a comma separated 
list of addresses, privateFor or topics instead of a List instance. For more 
information the related issue is CAMEL-17339.
 
+=== camel-spring-batch
+
+The `jobLauncher` and 'jobRegistry' is now autowired on the component if there 
is a single instance pre-configured in the application.
+This avoids having to wire this into the Camel component or endpoints.
diff --git 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SpringBatchEndpointBuilderFactory.java
 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SpringBatchEndpointBuilderFactory.java
index 308b7659955..d176e950913 100644
--- 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SpringBatchEndpointBuilderFactory.java
+++ 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SpringBatchEndpointBuilderFactory.java
@@ -199,6 +199,19 @@ public interface SpringBatchEndpointBuilderFactory {
     }
 
     public interface SpringBatchBuilders {
+        /**
+         * Spring Batch (camel-spring-batch)
+         * Send messages to Spring Batch for further processing.
+         * 
+         * Category: workflow
+         * Since: 2.10
+         * Maven coordinates: org.apache.camel:camel-spring-batch
+         * 
+         * @return the dsl builder for the headers' name.
+         */
+        default SpringBatchHeaderNameBuilder springBatch() {
+            return SpringBatchHeaderNameBuilder.INSTANCE;
+        }
         /**
          * Spring Batch (camel-spring-batch)
          * Send messages to Spring Batch for further processing.
@@ -241,6 +254,29 @@ public interface SpringBatchEndpointBuilderFactory {
         }
 
     }
+    /**
+     * The builder of headers' name for the Spring Batch component.
+     */
+    public static class SpringBatchHeaderNameBuilder {
+        /**
+         * The internal instance of the builder used to access to all the
+         * methods representing the name of headers.
+         */
+        private static final SpringBatchHeaderNameBuilder INSTANCE = new 
SpringBatchHeaderNameBuilder();
+
+        /**
+         * The name of the Batch Job to use.
+         * 
+         * The option is a: {@code String} type.
+         * 
+         * Group: producer
+         * 
+         * @return the name of the header {@code SpringBatchJobName}.
+         */
+        public String springBatchJobName() {
+            return "CamelSpringBatchJobName";
+        }
+    }
     static SpringBatchEndpointBuilder endpointBuilder(String componentName, 
String path) {
         class SpringBatchEndpointBuilderImpl extends AbstractEndpointBuilder 
implements SpringBatchEndpointBuilder, AdvancedSpringBatchEndpointBuilder {
             public SpringBatchEndpointBuilderImpl(String path) {


Reply via email to