public BeanDefinition parse(Element element, ParserContext parserContext) {

    final XmlReaderContext readerContext = parserContext.getReaderContext();
    final ClassLoader beanClassLoader =
        readerContext.getBeanClassLoader() != null
            ? readerContext.getBeanClassLoader()
            : Thread.currentThread().getContextClassLoader();

    String[] basePackages =
        StringUtils.commaDelimitedListToStringArray(element.getAttribute(BASE_PACKAGE_ATTRIBUTE));

    String dataSourceId = element.getAttribute(DATA_SOURCE_ATTRIBUTE);
    if (!StringUtils.hasText(dataSourceId)) {
      throw new BeanDefinitionParsingException(
          new Problem(
              "Attribute ["
                  + DATA_SOURCE_ATTRIBUTE
                  + "] of tag <gorm:sessionFactory> must be specified!",
              new Location(readerContext.getResource())));
    }

    // Actually scan for bean definitions and register them.
    BeanDefinitionRegistry targetRegistry = parserContext.getRegistry();

    // setup the GrailsApplication instance
    parseGrailsApplication(element, parserContext, readerContext, beanClassLoader, basePackages);

    GenericBeanDefinition postProccessingBeanDef = new GenericBeanDefinition();
    postProccessingBeanDef.setBeanClass(GORMEnhancingBeanPostProcessor.class);

    targetRegistry.registerBeanDefinition("gormEnhancingPostProcessor", postProccessingBeanDef);

    return parseSessionFactory(element, dataSourceId, targetRegistry, parserContext);
  }
  private ClassPathBeanDefinitionScanner configureScanner(
      ParserContext parserContext, BeanDefinitionRegistry registry) {
    XmlReaderContext readerContext = parserContext.getReaderContext();
    // Delegate bean definition registration to scanner class.
    ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry, false);
    scanner.setIncludeAnnotationConfig(false);
    scanner.addIncludeFilter(new AnnotationTypeFilter(Entity.class));

    scanner.setResourceLoader(readerContext.getResourceLoader());
    scanner.setBeanDefinitionDefaults(parserContext.getDelegate().getBeanDefinitionDefaults());
    scanner.setAutowireCandidatePatterns(
        parserContext.getDelegate().getAutowireCandidatePatterns());

    return scanner;
  }
  private void parseGrailsApplication(
      Element element,
      ParserContext parserContext,
      XmlReaderContext readerContext,
      ClassLoader beanClassLoader,
      String[] basePackages) {

    BeanDefinitionRegistry simpleRegistry = new SimpleBeanDefinitionRegistry();
    ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, simpleRegistry);

    scanner.scan(basePackages);

    BeanDefinitionRegistry targetRegistry = parserContext.getRegistry();
    AbstractBeanDefinition grailsApplicationBean = new GenericBeanDefinition();
    grailsApplicationBean.setBeanClass(DefaultGrailsApplication.class);
    grailsApplicationBean.setInitMethodName("initialise");
    ConstructorArgumentValues constructorArgs =
        grailsApplicationBean.getConstructorArgumentValues();

    Set<Class<?>> classes = new HashSet<Class<?>>();
    for (String beanName : simpleRegistry.getBeanDefinitionNames()) {
      BeanDefinition beanDef = simpleRegistry.getBeanDefinition(beanName);
      try {
        Class<?> entityClass = Class.forName(beanDef.getBeanClassName(), true, beanClassLoader);
        classes.add(entityClass);
        registerDomainBean(
            entityClass, targetRegistry, element.getAttribute(MESSAGE_SOURCE_ATTRIBUTE));
      } catch (ClassNotFoundException e) {
        throw new BeanDefinitionParsingException(
            new Problem(
                "Unable to load class whilst configuring GORM: " + e.getMessage(),
                new Location(readerContext.getResource()),
                null,
                e));
      }
    }

    constructorArgs.addGenericArgumentValue(classes.toArray(new Class[classes.size()]));
    constructorArgs.addGenericArgumentValue(beanClassLoader);
    targetRegistry.registerBeanDefinition(GrailsApplication.APPLICATION_ID, grailsApplicationBean);
  }
  @Override
  public BeanDefinition parse(Element element, ParserContext parserContext) {
    Object source = parserContext.extractSource(element);
    XmlReaderContext readerContext = parserContext.getReaderContext();

    CompositeComponentDefinition compDefinition =
        new CompositeComponentDefinition(element.getTagName(), source);
    parserContext.pushContainingComponent(compDefinition);

    RuntimeBeanReference contentNegotiationManager =
        getContentNegotiationManager(element, source, parserContext);

    RootBeanDefinition handlerMappingDef =
        new RootBeanDefinition(RequestMappingHandlerMapping.class);
    handlerMappingDef.setSource(source);
    handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    handlerMappingDef.getPropertyValues().add("order", 0);
    handlerMappingDef
        .getPropertyValues()
        .add("contentNegotiationManager", contentNegotiationManager);

    if (element.hasAttribute("enable-matrix-variables")) {
      Boolean enableMatrixVariables =
          Boolean.valueOf(element.getAttribute("enable-matrix-variables"));
      handlerMappingDef.getPropertyValues().add("removeSemicolonContent", !enableMatrixVariables);
    } else if (element.hasAttribute("enableMatrixVariables")) {
      Boolean enableMatrixVariables =
          Boolean.valueOf(element.getAttribute("enableMatrixVariables"));
      handlerMappingDef.getPropertyValues().add("removeSemicolonContent", !enableMatrixVariables);
    }

    configurePathMatchingProperties(handlerMappingDef, element, parserContext);
    readerContext
        .getRegistry()
        .registerBeanDefinition(HANDLER_MAPPING_BEAN_NAME, handlerMappingDef);

    RuntimeBeanReference corsConfigurationsRef =
        MvcNamespaceUtils.registerCorsConfigurations(null, parserContext, source);
    handlerMappingDef.getPropertyValues().add("corsConfigurations", corsConfigurationsRef);

    RuntimeBeanReference conversionService = getConversionService(element, source, parserContext);
    RuntimeBeanReference validator = getValidator(element, source, parserContext);
    RuntimeBeanReference messageCodesResolver = getMessageCodesResolver(element);

    RootBeanDefinition bindingDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class);
    bindingDef.setSource(source);
    bindingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    bindingDef.getPropertyValues().add("conversionService", conversionService);
    bindingDef.getPropertyValues().add("validator", validator);
    bindingDef.getPropertyValues().add("messageCodesResolver", messageCodesResolver);

    ManagedList<?> messageConverters = getMessageConverters(element, source, parserContext);
    ManagedList<?> argumentResolvers = getArgumentResolvers(element, parserContext);
    ManagedList<?> returnValueHandlers = getReturnValueHandlers(element, parserContext);
    String asyncTimeout = getAsyncTimeout(element);
    RuntimeBeanReference asyncExecutor = getAsyncExecutor(element);
    ManagedList<?> callableInterceptors = getCallableInterceptors(element, source, parserContext);
    ManagedList<?> deferredResultInterceptors =
        getDeferredResultInterceptors(element, source, parserContext);

    RootBeanDefinition handlerAdapterDef =
        new RootBeanDefinition(RequestMappingHandlerAdapter.class);
    handlerAdapterDef.setSource(source);
    handlerAdapterDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    handlerAdapterDef
        .getPropertyValues()
        .add("contentNegotiationManager", contentNegotiationManager);
    handlerAdapterDef.getPropertyValues().add("webBindingInitializer", bindingDef);
    handlerAdapterDef.getPropertyValues().add("messageConverters", messageConverters);
    addRequestBodyAdvice(handlerAdapterDef);
    addResponseBodyAdvice(handlerAdapterDef);

    if (element.hasAttribute("ignore-default-model-on-redirect")) {
      Boolean ignoreDefaultModel =
          Boolean.valueOf(element.getAttribute("ignore-default-model-on-redirect"));
      handlerAdapterDef.getPropertyValues().add("ignoreDefaultModelOnRedirect", ignoreDefaultModel);
    } else if (element.hasAttribute("ignoreDefaultModelOnRedirect")) {
      // "ignoreDefaultModelOnRedirect" spelling is deprecated
      Boolean ignoreDefaultModel =
          Boolean.valueOf(element.getAttribute("ignoreDefaultModelOnRedirect"));
      handlerAdapterDef.getPropertyValues().add("ignoreDefaultModelOnRedirect", ignoreDefaultModel);
    }

    if (argumentResolvers != null) {
      handlerAdapterDef.getPropertyValues().add("customArgumentResolvers", argumentResolvers);
    }
    if (returnValueHandlers != null) {
      handlerAdapterDef.getPropertyValues().add("customReturnValueHandlers", returnValueHandlers);
    }
    if (asyncTimeout != null) {
      handlerAdapterDef.getPropertyValues().add("asyncRequestTimeout", asyncTimeout);
    }
    if (asyncExecutor != null) {
      handlerAdapterDef.getPropertyValues().add("taskExecutor", asyncExecutor);
    }

    handlerAdapterDef.getPropertyValues().add("callableInterceptors", callableInterceptors);
    handlerAdapterDef
        .getPropertyValues()
        .add("deferredResultInterceptors", deferredResultInterceptors);
    readerContext
        .getRegistry()
        .registerBeanDefinition(HANDLER_ADAPTER_BEAN_NAME, handlerAdapterDef);

    String uriCompContribName = MvcUriComponentsBuilder.MVC_URI_COMPONENTS_CONTRIBUTOR_BEAN_NAME;
    RootBeanDefinition uriCompContribDef =
        new RootBeanDefinition(CompositeUriComponentsContributorFactoryBean.class);
    uriCompContribDef.setSource(source);
    uriCompContribDef.getPropertyValues().addPropertyValue("handlerAdapter", handlerAdapterDef);
    uriCompContribDef.getPropertyValues().addPropertyValue("conversionService", conversionService);
    readerContext.getRegistry().registerBeanDefinition(uriCompContribName, uriCompContribDef);

    RootBeanDefinition csInterceptorDef =
        new RootBeanDefinition(ConversionServiceExposingInterceptor.class);
    csInterceptorDef.setSource(source);
    csInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, conversionService);
    RootBeanDefinition mappedCsInterceptorDef = new RootBeanDefinition(MappedInterceptor.class);
    mappedCsInterceptorDef.setSource(source);
    mappedCsInterceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    mappedCsInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, (Object) null);
    mappedCsInterceptorDef
        .getConstructorArgumentValues()
        .addIndexedArgumentValue(1, csInterceptorDef);
    String mappedInterceptorName = readerContext.registerWithGeneratedName(mappedCsInterceptorDef);

    RootBeanDefinition exceptionHandlerExceptionResolver =
        new RootBeanDefinition(ExceptionHandlerExceptionResolver.class);
    exceptionHandlerExceptionResolver.setSource(source);
    exceptionHandlerExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    exceptionHandlerExceptionResolver
        .getPropertyValues()
        .add("contentNegotiationManager", contentNegotiationManager);
    exceptionHandlerExceptionResolver
        .getPropertyValues()
        .add("messageConverters", messageConverters);
    exceptionHandlerExceptionResolver.getPropertyValues().add("order", 0);
    addResponseBodyAdvice(exceptionHandlerExceptionResolver);

    String methodExceptionResolverName =
        readerContext.registerWithGeneratedName(exceptionHandlerExceptionResolver);

    RootBeanDefinition responseStatusExceptionResolver =
        new RootBeanDefinition(ResponseStatusExceptionResolver.class);
    responseStatusExceptionResolver.setSource(source);
    responseStatusExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    responseStatusExceptionResolver.getPropertyValues().add("order", 1);
    String responseStatusExceptionResolverName =
        readerContext.registerWithGeneratedName(responseStatusExceptionResolver);

    RootBeanDefinition defaultExceptionResolver =
        new RootBeanDefinition(DefaultHandlerExceptionResolver.class);
    defaultExceptionResolver.setSource(source);
    defaultExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    defaultExceptionResolver.getPropertyValues().add("order", 2);
    String defaultExceptionResolverName =
        readerContext.registerWithGeneratedName(defaultExceptionResolver);

    parserContext.registerComponent(
        new BeanComponentDefinition(handlerMappingDef, HANDLER_MAPPING_BEAN_NAME));
    parserContext.registerComponent(
        new BeanComponentDefinition(handlerAdapterDef, HANDLER_ADAPTER_BEAN_NAME));
    parserContext.registerComponent(
        new BeanComponentDefinition(uriCompContribDef, uriCompContribName));
    parserContext.registerComponent(
        new BeanComponentDefinition(
            exceptionHandlerExceptionResolver, methodExceptionResolverName));
    parserContext.registerComponent(
        new BeanComponentDefinition(
            responseStatusExceptionResolver, responseStatusExceptionResolverName));
    parserContext.registerComponent(
        new BeanComponentDefinition(defaultExceptionResolver, defaultExceptionResolverName));
    parserContext.registerComponent(
        new BeanComponentDefinition(mappedCsInterceptorDef, mappedInterceptorName));

    // Ensure BeanNameUrlHandlerMapping (SPR-8289) and default HandlerAdapters are not "turned off"
    MvcNamespaceUtils.registerDefaultComponents(parserContext, source);

    parserContext.popAndRegisterContainingComponent();

    return null;
  }