B.4. Coding a BeanDefinitionParser

Spring Framework

B.4. Coding a BeanDefinitionParser

As you can see, the namespace handler shown above registers so-called BeanDefinitionParsers. A BeanDefinitionParser in this case will be consulted if the namespace handler encounters an XML element of the type that has been mapped to this specific bean definition parser (which is dateformat in this case). In other words, the BeanDefinitionParser is responsible for parsing one distinct top-level XML element defined in the schema. In the parser, we'll have access to the XML element (and its subelements) and the ParserContext. The latter can be used to obtain a reference to the BeanDefinitionRegistry, for instance, as seen in the example below.

package org.springframework.samples.xml;

import java.text.SimpleDateFormat;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;

public class SimpleDateFormatBeanDefinitionParser implements BeanDefinitionParser {
   
   public BeanDefinition parse(Element element, ParserContext parserContext) {
      
      // create a RootBeanDefinition that will serve as configuration
      // holder for the 'pattern' attribute and the 'lenient' attribute
      RootBeanDefinition beanDef = new RootBeanDefinition();
      beanDef.setBeanClass(SimpleDateFormat.class);      

      // never null since the schema requires it 
      String pattern = element.getAttribute("pattern");
      beanDef.getConstructorArgumentValues().addGenericArgumentValue(pattern);

      String lenientString = element.getAttribute("lenient");
      if (StringUtils.hasText(lenientString)) {
         // won't throw exception if validation is turned on (boolean type set in schema)         
         beanDef.getPropertyValues().addPropertyValue("lenient", new Boolean(lenientString));
      }
      
      // retrieve the ID attribute that will serve as the bean identifier in the context 
      String id = element.getAttribute("id");
      
      // create a bean definition holder to be able to register the
      // bean definition with the bean definition registry
      // (obtained through the ParserContext)
      BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDef, id);
      
      // register the BeanDefinitionHolder (which contains the bean definition)
      // with the BeanDefinitionRegistry
      BeanDefinitionReaderUtils.registerBeanDefinition(holder, parserContext.getRegistry());
      
      return beanDef;
   }
}

注意

In the example here, we're defining a BeanDefinition and registering it with the BeanDefinitionRegistry. Note that you don't necessarily have to register a bean definition with the registry or return a bean definition from the parse() method. You are free to do whatever you want with the information given to you (i.e. the XML element) and the ParserContext.

The ParserContext provides access to following properties:

  • readerContext - provides access to the bean factory and also to the NamespaceHandlerResolver, which can optionally be used to resolve nested namespaces.

  • parserDelegate - controlling component that drives the parsing of (parts of) the configuration file. Typically you don't need to access this.

  • registry - the BeanDefinitionRegistry that allows you to register newly created BeanDefinition instances with.

  • nested - indicates whether or the XML element that is currently being processed is part of a outer bean definition (in other words, it's defined similar to traditional inner-beans).