diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/CoreNamespaceUtils.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/CoreNamespaceUtils.java
index 10e51c0b4..f2edf0900 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/CoreNamespaceUtils.java
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/CoreNamespaceUtils.java
@@ -146,7 +146,16 @@ public class CoreNamespaceUtils {
* @return TRUE if the element is abstract or has a parent
*/
public static boolean isUnderspecified(Element element) {
- return Boolean.valueOf(element.getAttribute("abstract")) || StringUtils.hasText(element.getAttribute("parent"));
+ return isAbstract(element) || StringUtils.hasText(element.getAttribute("parent"));
+ }
+
+ /**
+ * @param element
+ * @return TRUE if the element is abstract
+ */
+ public static boolean isAbstract(Element element) {
+ String abstractAttr = element.getAttribute("abstract");
+ return StringUtils.hasText(abstractAttr) && Boolean.valueOf(abstractAttr);
}
}
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/FlowParser.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/FlowParser.java
index ceca94da5..41055719a 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/FlowParser.java
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/FlowParser.java
@@ -132,7 +132,7 @@ public class FlowParser extends AbstractSingleBeanDefinitionParser {
}
}
- if (!stepExists && !CoreNamespaceUtils.isUnderspecified(element)) {
+ if (!stepExists && !StringUtils.hasText(element.getAttribute("parent"))) {
parserContext.getReaderContext().error("The flow [" + flowName + "] must contain at least one step",
element);
}
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/JobParser.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/JobParser.java
index 317aceeb7..11ef858d3 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/JobParser.java
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/JobParser.java
@@ -15,6 +15,7 @@
*/
package org.springframework.batch.core.configuration.xml;
+import java.util.Arrays;
import java.util.List;
import org.springframework.beans.factory.config.BeanDefinition;
@@ -62,10 +63,8 @@ public class JobParser extends AbstractSingleBeanDefinitionParser {
String jobName = element.getAttribute("id");
builder.addConstructorArgValue(jobName);
- String isAbstract = element.getAttribute("abstract");
- if (StringUtils.hasText(isAbstract)) {
- builder.setAbstract(Boolean.valueOf(isAbstract));
- }
+ boolean isAbstract = CoreNamespaceUtils.isAbstract(element);
+ builder.setAbstract(isAbstract);
String parentRef = element.getAttribute("parent");
if (StringUtils.hasText(parentRef)) {
@@ -87,9 +86,20 @@ public class JobParser extends AbstractSingleBeanDefinitionParser {
builder.addPropertyReference("jobParametersIncrementer", incrementer);
}
- FlowParser flowParser = new FlowParser(jobName, jobName);
- BeanDefinition flowDef = flowParser.parse(element, parserContext);
- builder.addPropertyValue("flow", flowDef);
+ if (isAbstract) {
+ for (String tagName : Arrays.asList("step", "decision", "split")) {
+ if (!DomUtils.getChildElementsByTagName(element, tagName).isEmpty()) {
+ parserContext.getReaderContext().error(
+ "The <" + tagName + "/> element may not appear on a with abstract=\"true\" ["
+ + jobName + "]", element);
+ }
+ }
+ }
+ else {
+ FlowParser flowParser = new FlowParser(jobName, jobName);
+ BeanDefinition flowDef = flowParser.parse(element, parserContext);
+ builder.addPropertyValue("flow", flowDef);
+ }
List listenersElements = DomUtils.getChildElementsByTagName(element, "listeners");
if (listenersElements.size() == 1) {