class JobParser extends AbstractSingleBeanDefinitionParser {

	private static final String MERGE_ATTR = "merge";

	private static final String REF_ATTR = "ref";

	private static final String BEAN_ELE = "bean";

	private static final String REF_ELE = "ref";

	private static final JobExecutionListenerParser jobListenerParser = new JobExecutionListenerParser();

	@Override
	protected Class<JobParserJobFactoryBean> getBeanClass(Element element) {
		return JobParserJobFactoryBean.class;
	}

	/**
	 * Create a bean definition for a
	 * {@link org.springframework.batch.core.job.flow.FlowJob}. Nested step elements are
	 * delegated to an {@link InlineStepParser}.
	 *
	 * @see AbstractSingleBeanDefinitionParser#doParse(Element, ParserContext,
	 * BeanDefinitionBuilder)
	 */
	@Override
	protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {<FILL_FUNCTION_BODY>}

	/**
	 * Parse the element to retrieve {@link BeanMetadataElement}.
	 * @param element The {@link Element} to be parsed.
	 * @param parserContext The {@link ParserContext}.
	 * @return the {@link BeanMetadataElement} extracted from the element parameter.
	 */
	public BeanMetadataElement parseBeanElement(Element element, ParserContext parserContext) {
		String refAttribute = element.getAttribute(REF_ATTR);
		Element beanElement = DomUtils.getChildElementByTagName(element, BEAN_ELE);
		Element refElement = DomUtils.getChildElementByTagName(element, REF_ELE);

		if (StringUtils.hasText(refAttribute)) {
			return new RuntimeBeanReference(refAttribute);
		}
		else if (beanElement != null) {
			BeanDefinitionHolder beanDefinitionHolder = parserContext.getDelegate()
				.parseBeanDefinitionElement(beanElement);
			parserContext.getDelegate().decorateBeanDefinitionIfRequired(beanElement, beanDefinitionHolder);
			return beanDefinitionHolder;
		}
		else if (refElement != null) {
			return (BeanMetadataElement) parserContext.getDelegate().parsePropertySubElement(refElement, null);
		}

		parserContext.getReaderContext()
			.error("One of ref attribute or a nested bean definition or ref element must be specified", element);
		return null;
	}

}


		if (!CoreNamespaceUtils.namespaceMatchesVersion(element)) {
			parserContext.getReaderContext()
				.error("You are using a version of the spring-batch XSD that is not compatible with Spring Batch 3.0."
						+ "  Please upgrade your schema declarations (or use the spring-batch.xsd alias if you are "
						+ "feeling lucky).", element);
			return;
		}

		CoreNamespaceUtils.autoregisterBeansForNamespace(parserContext, parserContext.extractSource(element));

		String jobName = element.getAttribute("id");
		builder.addConstructorArgValue(jobName);

		boolean isAbstract = CoreNamespaceUtils.isAbstract(element);
		builder.setAbstract(isAbstract);

		String parentRef = element.getAttribute("parent");
		if (StringUtils.hasText(parentRef)) {
			builder.setParentName(parentRef);
		}

		String repositoryAttribute = element.getAttribute("job-repository");
		if (StringUtils.hasText(repositoryAttribute)) {
			builder.addPropertyReference("jobRepository", repositoryAttribute);
		}

		Element validator = DomUtils.getChildElementByTagName(element, "validator");
		if (validator != null) {
			builder.addPropertyValue("jobParametersValidator", parseBeanElement(validator, parserContext));
		}

		String restartableAttribute = element.getAttribute("restartable");
		if (StringUtils.hasText(restartableAttribute)) {
			builder.addPropertyValue("restartable", restartableAttribute);
		}

		String incrementer = (element.getAttribute("incrementer"));
		if (StringUtils.hasText(incrementer)) {
			builder.addPropertyReference("jobParametersIncrementer", incrementer);
		}

		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 <job/> with abstract=\"true\" ["
								+ jobName + "]", element);
				}
			}
		}
		else {
			InlineFlowParser flowParser = new InlineFlowParser(jobName, jobName);
			BeanDefinition flowDef = flowParser.parse(element, parserContext);
			builder.addPropertyValue("flow", flowDef);
		}

		Element description = DomUtils.getChildElementByTagName(element, "description");
		if (description != null) {
			builder.getBeanDefinition().setDescription(description.getTextContent());
		}

		List<Element> listenersElements = DomUtils.getChildElementsByTagName(element, "listeners");
		if (listenersElements.size() == 1) {
			Element listenersElement = listenersElements.get(0);
			CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(listenersElement.getTagName(),
					parserContext.extractSource(element));
			parserContext.pushContainingComponent(compositeDef);
			ManagedList<BeanDefinition> listeners = new ManagedList<>();
			listeners.setMergeEnabled(listenersElement.hasAttribute(MERGE_ATTR)
					&& Boolean.parseBoolean(listenersElement.getAttribute(MERGE_ATTR)));
			List<Element> listenerElements = DomUtils.getChildElementsByTagName(listenersElement, "listener");
			for (Element listenerElement : listenerElements) {
				listeners.add(jobListenerParser.parse(listenerElement, parserContext));
			}
			builder.addPropertyValue("jobExecutionListeners", listeners);
			parserContext.popAndRegisterContainingComponent();
		}
		else if (listenersElements.size() > 1) {
			parserContext.getReaderContext()
				.error("The '<listeners/>' element may not appear more than once in a single <job/>.", element);
		}

	
<methods>public void <init>() <variables>