private RootBeanDefinition parseAttributeSource(Element attrEle, ParserContext parserContext) {
    List<Element> methods = DomUtils.getChildElementsByTagName(attrEle, METHOD_ELEMENT);
    ManagedMap<TypedStringValue, RuleBasedTransactionAttribute> transactionAttributeMap =
        new ManagedMap<TypedStringValue, RuleBasedTransactionAttribute>(methods.size());
    transactionAttributeMap.setSource(parserContext.extractSource(attrEle));

    for (Element methodEle : methods) {
      String name = methodEle.getAttribute(METHOD_NAME_ATTRIBUTE);
      TypedStringValue nameHolder = new TypedStringValue(name);
      nameHolder.setSource(parserContext.extractSource(methodEle));

      RuleBasedTransactionAttribute attribute = new RuleBasedTransactionAttribute();
      String propagation = methodEle.getAttribute(PROPAGATION_ATTRIBUTE);
      String isolation = methodEle.getAttribute(ISOLATION_ATTRIBUTE);
      String timeout = methodEle.getAttribute(TIMEOUT_ATTRIBUTE);
      String readOnly = methodEle.getAttribute(READ_ONLY_ATTRIBUTE);
      if (StringUtils.hasText(propagation)) {
        attribute.setPropagationBehaviorName(
            RuleBasedTransactionAttribute.PREFIX_PROPAGATION + propagation);
      }
      if (StringUtils.hasText(isolation)) {
        attribute.setIsolationLevelName(RuleBasedTransactionAttribute.PREFIX_ISOLATION + isolation);
      }
      if (StringUtils.hasText(timeout)) {
        try {
          attribute.setTimeout(Integer.parseInt(timeout));
        } catch (NumberFormatException ex) {
          parserContext
              .getReaderContext()
              .error("Timeout must be an integer value: [" + timeout + "]", methodEle);
        }
      }
      if (StringUtils.hasText(readOnly)) {
        attribute.setReadOnly(Boolean.valueOf(methodEle.getAttribute(READ_ONLY_ATTRIBUTE)));
      }

      List<RollbackRuleAttribute> rollbackRules = new LinkedList<RollbackRuleAttribute>();
      if (methodEle.hasAttribute(ROLLBACK_FOR_ATTRIBUTE)) {
        String rollbackForValue = methodEle.getAttribute(ROLLBACK_FOR_ATTRIBUTE);
        addRollbackRuleAttributesTo(rollbackRules, rollbackForValue);
      }
      if (methodEle.hasAttribute(NO_ROLLBACK_FOR_ATTRIBUTE)) {
        String noRollbackForValue = methodEle.getAttribute(NO_ROLLBACK_FOR_ATTRIBUTE);
        addNoRollbackRuleAttributesTo(rollbackRules, noRollbackForValue);
      }
      attribute.setRollbackRules(rollbackRules);

      transactionAttributeMap.put(nameHolder, attribute);
    }

    RootBeanDefinition attributeSourceDefinition =
        new RootBeanDefinition(NameMatchTransactionAttributeSource.class);
    attributeSourceDefinition.setSource(parserContext.extractSource(attrEle));
    attributeSourceDefinition.getPropertyValues().add("nameMap", transactionAttributeMap);
    return attributeSourceDefinition;
  }
 private RuntimeBeanReference getConversionService(
     Element element, Object source, ParserContext parserContext) {
   RuntimeBeanReference conversionServiceRef;
   if (element.hasAttribute("conversion-service")) {
     conversionServiceRef = new RuntimeBeanReference(element.getAttribute("conversion-service"));
   } else {
     RootBeanDefinition conversionDef =
         new RootBeanDefinition(FormattingConversionServiceFactoryBean.class);
     conversionDef.setSource(source);
     conversionDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
     String conversionName =
         parserContext.getReaderContext().registerWithGeneratedName(conversionDef);
     parserContext.registerComponent(new BeanComponentDefinition(conversionDef, conversionName));
     conversionServiceRef = new RuntimeBeanReference(conversionName);
   }
   return conversionServiceRef;
 }
 private RuntimeBeanReference getValidator(
     Element element, Object source, ParserContext parserContext) {
   if (element.hasAttribute("validator")) {
     return new RuntimeBeanReference(element.getAttribute("validator"));
   } else if (javaxValidationPresent) {
     RootBeanDefinition validatorDef =
         new RootBeanDefinition(
             "org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean");
     validatorDef.setSource(source);
     validatorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
     String validatorName =
         parserContext.getReaderContext().registerWithGeneratedName(validatorDef);
     parserContext.registerComponent(new BeanComponentDefinition(validatorDef, validatorName));
     return new RuntimeBeanReference(validatorName);
   } else {
     return null;
   }
 }
  private RuntimeBeanReference getContentNegotiationManager(
      Element element, Object source, ParserContext parserContext) {

    RuntimeBeanReference beanRef;
    if (element.hasAttribute("content-negotiation-manager")) {
      String name = element.getAttribute("content-negotiation-manager");
      beanRef = new RuntimeBeanReference(name);
    } else {
      RootBeanDefinition factoryBeanDef =
          new RootBeanDefinition(ContentNegotiationManagerFactoryBean.class);
      factoryBeanDef.setSource(source);
      factoryBeanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
      factoryBeanDef.getPropertyValues().add("mediaTypes", getDefaultMediaTypes());

      String name = CONTENT_NEGOTIATION_MANAGER_BEAN_NAME;
      parserContext.getReaderContext().getRegistry().registerBeanDefinition(name, factoryBeanDef);
      parserContext.registerComponent(new BeanComponentDefinition(factoryBeanDef, name));
      beanRef = new RuntimeBeanReference(name);
    }
    return beanRef;
  }
  protected BeanDefinition parseContainer(
      Element listenerEle, Element containerEle, ParserContext parserContext) {
    RootBeanDefinition containerDef = new RootBeanDefinition();
    containerDef.setSource(parserContext.extractSource(containerEle));

    parseListenerConfiguration(listenerEle, parserContext, containerDef);
    parseContainerConfiguration(containerEle, parserContext, containerDef);

    String containerType = containerEle.getAttribute(CONTAINER_TYPE_ATTRIBUTE);
    String containerClass = containerEle.getAttribute(CONTAINER_CLASS_ATTRIBUTE);
    if (!"".equals(containerClass)) {
      containerDef.setBeanClassName(containerClass);
    } else if ("".equals(containerType) || containerType.startsWith("default")) {
      containerDef.setBeanClassName(
          "org.springframework.jms.listener.DefaultMessageListenerContainer");
    } else if (containerType.startsWith("simple")) {
      containerDef.setBeanClassName(
          "org.springframework.jms.listener.SimpleMessageListenerContainer");
    } else {
      parserContext
          .getReaderContext()
          .error(
              "Invalid 'container-type' attribute: only \"default\" and \"simple\" supported.",
              containerEle);
    }

    String connectionFactoryBeanName = "connectionFactory";
    if (containerEle.hasAttribute(CONNECTION_FACTORY_ATTRIBUTE)) {
      connectionFactoryBeanName = containerEle.getAttribute(CONNECTION_FACTORY_ATTRIBUTE);
      if (!StringUtils.hasText(connectionFactoryBeanName)) {
        parserContext
            .getReaderContext()
            .error(
                "Listener container 'connection-factory' attribute contains empty value.",
                containerEle);
      }
    }
    if (StringUtils.hasText(connectionFactoryBeanName)) {
      containerDef
          .getPropertyValues()
          .add("connectionFactory", new RuntimeBeanReference(connectionFactoryBeanName));
    }

    String taskExecutorBeanName = containerEle.getAttribute(TASK_EXECUTOR_ATTRIBUTE);
    if (StringUtils.hasText(taskExecutorBeanName)) {
      containerDef
          .getPropertyValues()
          .add("taskExecutor", new RuntimeBeanReference(taskExecutorBeanName));
    }

    String errorHandlerBeanName = containerEle.getAttribute(ERROR_HANDLER_ATTRIBUTE);
    if (StringUtils.hasText(errorHandlerBeanName)) {
      containerDef
          .getPropertyValues()
          .add("errorHandler", new RuntimeBeanReference(errorHandlerBeanName));
    }

    String destinationResolverBeanName = containerEle.getAttribute(DESTINATION_RESOLVER_ATTRIBUTE);
    if (StringUtils.hasText(destinationResolverBeanName)) {
      containerDef
          .getPropertyValues()
          .add("destinationResolver", new RuntimeBeanReference(destinationResolverBeanName));
    }

    String cache = containerEle.getAttribute(CACHE_ATTRIBUTE);
    if (StringUtils.hasText(cache)) {
      if (containerType.startsWith("simple")) {
        if (!("auto".equals(cache) || "consumer".equals(cache))) {
          parserContext
              .getReaderContext()
              .warning(
                  "'cache' attribute not actively supported for listener container of type \"simple\". "
                      + "Effective runtime behavior will be equivalent to \"consumer\" / \"auto\".",
                  containerEle);
        }
      } else {
        containerDef.getPropertyValues().add("cacheLevelName", "CACHE_" + cache.toUpperCase());
      }
    }

    Integer acknowledgeMode = parseAcknowledgeMode(containerEle, parserContext);
    if (acknowledgeMode != null) {
      if (acknowledgeMode == Session.SESSION_TRANSACTED) {
        containerDef.getPropertyValues().add("sessionTransacted", Boolean.TRUE);
      } else {
        containerDef.getPropertyValues().add("sessionAcknowledgeMode", acknowledgeMode);
      }
    }

    String transactionManagerBeanName = containerEle.getAttribute(TRANSACTION_MANAGER_ATTRIBUTE);
    if (StringUtils.hasText(transactionManagerBeanName)) {
      if (containerType.startsWith("simple")) {
        parserContext
            .getReaderContext()
            .error(
                "'transaction-manager' attribute not supported for listener container of type \"simple\".",
                containerEle);
      } else {
        containerDef
            .getPropertyValues()
            .add("transactionManager", new RuntimeBeanReference(transactionManagerBeanName));
      }
    }

    String concurrency = containerEle.getAttribute(CONCURRENCY_ATTRIBUTE);
    if (StringUtils.hasText(concurrency)) {
      containerDef.getPropertyValues().add("concurrency", concurrency);
    }

    String prefetch = containerEle.getAttribute(PREFETCH_ATTRIBUTE);
    if (StringUtils.hasText(prefetch)) {
      if (containerType.startsWith("default")) {
        containerDef.getPropertyValues().add("maxMessagesPerTask", new Integer(prefetch));
      }
    }

    String receiveTimeout = containerEle.getAttribute(RECEIVE_TIMEOUT_ATTRIBUTE);
    if (StringUtils.hasText(receiveTimeout)) {
      if (containerType.startsWith("default")) {
        containerDef.getPropertyValues().add("receiveTimeout", new Integer(receiveTimeout));
      }
    }

    String phase = containerEle.getAttribute(PHASE_ATTRIBUTE);
    if (StringUtils.hasText(phase)) {
      containerDef.getPropertyValues().add("phase", phase);
    }

    return containerDef;
  }
 private RootBeanDefinition createConverterDefinition(Class<?> converterClass, Object source) {
   RootBeanDefinition beanDefinition = new RootBeanDefinition(converterClass);
   beanDefinition.setSource(source);
   beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
   return beanDefinition;
 }
  @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;
  }
  public BeanDefinition parse(Element elt, ParserContext pc) {
    String loginUrl = null;
    String defaultTargetUrl = null;
    String authenticationFailureUrl = null;
    String alwaysUseDefault = null;
    String successHandlerRef = null;
    String failureHandlerRef = null;
    // Only available with form-login
    String usernameParameter = null;
    String passwordParameter = null;
    String authDetailsSourceRef = null;

    Object source = null;

    if (elt != null) {
      source = pc.extractSource(elt);
      loginUrl = elt.getAttribute(ATT_LOGIN_URL);
      WebConfigUtils.validateHttpRedirect(loginUrl, pc, source);
      defaultTargetUrl = elt.getAttribute(ATT_FORM_LOGIN_TARGET_URL);
      WebConfigUtils.validateHttpRedirect(defaultTargetUrl, pc, source);
      authenticationFailureUrl = elt.getAttribute(ATT_FORM_LOGIN_AUTHENTICATION_FAILURE_URL);
      WebConfigUtils.validateHttpRedirect(authenticationFailureUrl, pc, source);
      alwaysUseDefault = elt.getAttribute(ATT_ALWAYS_USE_DEFAULT_TARGET_URL);
      loginPage = elt.getAttribute(ATT_LOGIN_PAGE);
      successHandlerRef = elt.getAttribute(ATT_SUCCESS_HANDLER_REF);
      failureHandlerRef = elt.getAttribute(ATT_FAILURE_HANDLER_REF);
      authDetailsSourceRef =
          elt.getAttribute(AuthenticationConfigBuilder.ATT_AUTH_DETAILS_SOURCE_REF);

      if (!StringUtils.hasText(loginPage)) {
        loginPage = null;
      }
      WebConfigUtils.validateHttpRedirect(loginPage, pc, source);
      usernameParameter = elt.getAttribute(ATT_USERNAME_PARAMETER);
      passwordParameter = elt.getAttribute(ATT_PASSWORD_PARAMETER);
    }

    filterBean =
        createFilterBean(
            loginUrl,
            defaultTargetUrl,
            alwaysUseDefault,
            loginPage,
            authenticationFailureUrl,
            successHandlerRef,
            failureHandlerRef,
            authDetailsSourceRef);

    if (StringUtils.hasText(usernameParameter)) {
      filterBean.getPropertyValues().addPropertyValue("usernameParameter", usernameParameter);
    }
    if (StringUtils.hasText(passwordParameter)) {
      filterBean.getPropertyValues().addPropertyValue("passwordParameter", passwordParameter);
    }

    filterBean.setSource(source);

    BeanDefinitionBuilder entryPointBuilder =
        BeanDefinitionBuilder.rootBeanDefinition(LoginUrlAuthenticationEntryPoint.class);
    entryPointBuilder.getRawBeanDefinition().setSource(source);
    entryPointBuilder.addConstructorArgValue(loginPage != null ? loginPage : DEF_LOGIN_PAGE);
    entryPointBuilder.addPropertyValue("portMapper", portMapper);
    entryPointBuilder.addPropertyValue("portResolver", portResolver);
    entryPointBean = (RootBeanDefinition) entryPointBuilder.getBeanDefinition();

    return null;
  }
  /**
   * Read a particular {@link ConfigurationClassMethod}, registering bean definitions with the
   * BeanDefinitionRegistry based on its contents.
   */
  private void loadBeanDefinitionsForBeanMethod(ConfigurationClassMethod beanMethod) {
    ConfigurationClass configClass = beanMethod.getConfigurationClass();
    MethodMetadata metadata = beanMethod.getMetadata();

    RootBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass);
    beanDef.setResource(configClass.getResource());
    beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
    beanDef.setFactoryBeanName(configClass.getBeanName());
    beanDef.setUniqueFactoryMethodName(metadata.getMethodName());
    beanDef.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
    beanDef.setAttribute(
        RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);

    // consider name and any aliases
    Map<String, Object> beanAttributes = metadata.getAnnotationAttributes(Bean.class.getName());
    List<String> names =
        new ArrayList<String>(Arrays.asList((String[]) beanAttributes.get("name")));
    String beanName =
        (names.size() > 0 ? names.remove(0) : beanMethod.getMetadata().getMethodName());
    for (String alias : names) {
      this.registry.registerAlias(beanName, alias);
    }

    // has this already been overridden (e.g. via XML)?
    if (this.registry.containsBeanDefinition(beanName)) {
      BeanDefinition existingBeanDef = registry.getBeanDefinition(beanName);
      // is the existing bean definition one that was created from a configuration class?
      if (!(existingBeanDef instanceof ConfigurationClassBeanDefinition)) {
        // no -> then it's an external override, probably XML
        // overriding is legal, return immediately
        if (logger.isDebugEnabled()) {
          logger.debug(
              String.format(
                  "Skipping loading bean definition for %s: a definition for bean "
                      + "'%s' already exists. This is likely due to an override in XML.",
                  beanMethod, beanName));
        }
        return;
      }
    }

    if (metadata.isAnnotated(Primary.class.getName())) {
      beanDef.setPrimary(true);
    }

    // is this bean to be instantiated lazily?
    if (metadata.isAnnotated(Lazy.class.getName())) {
      beanDef.setLazyInit(
          (Boolean) metadata.getAnnotationAttributes(Lazy.class.getName()).get("value"));
    } else if (configClass.getMetadata().isAnnotated(Lazy.class.getName())) {
      beanDef.setLazyInit(
          (Boolean)
              configClass.getMetadata().getAnnotationAttributes(Lazy.class.getName()).get("value"));
    }

    if (metadata.isAnnotated(DependsOn.class.getName())) {
      String[] dependsOn =
          (String[]) metadata.getAnnotationAttributes(DependsOn.class.getName()).get("value");
      if (dependsOn.length > 0) {
        beanDef.setDependsOn(dependsOn);
      }
    }

    Autowire autowire = (Autowire) beanAttributes.get("autowire");
    if (autowire.isAutowire()) {
      beanDef.setAutowireMode(autowire.value());
    }

    String initMethodName = (String) beanAttributes.get("initMethod");
    if (StringUtils.hasText(initMethodName)) {
      beanDef.setInitMethodName(initMethodName);
    }

    String destroyMethodName = (String) beanAttributes.get("destroyMethod");
    if (StringUtils.hasText(destroyMethodName)) {
      beanDef.setDestroyMethodName(destroyMethodName);
    }

    // consider scoping
    ScopedProxyMode proxyMode = ScopedProxyMode.NO;
    Map<String, Object> scopeAttributes = metadata.getAnnotationAttributes(Scope.class.getName());
    if (scopeAttributes != null) {
      beanDef.setScope((String) scopeAttributes.get("value"));
      proxyMode = (ScopedProxyMode) scopeAttributes.get("proxyMode");
      if (proxyMode == ScopedProxyMode.DEFAULT) {
        proxyMode = ScopedProxyMode.NO;
      }
    }

    // replace the original bean definition with the target one, if necessary
    BeanDefinition beanDefToRegister = beanDef;
    if (proxyMode != ScopedProxyMode.NO) {
      BeanDefinitionHolder proxyDef =
          ScopedProxyCreator.createScopedProxy(
              new BeanDefinitionHolder(beanDef, beanName),
              this.registry,
              proxyMode == ScopedProxyMode.TARGET_CLASS);
      beanDefToRegister = proxyDef.getBeanDefinition();
    }

    if (logger.isDebugEnabled()) {
      logger.debug(
          String.format(
              "Registering bean definition for @Bean method %s.%s()",
              configClass.getMetadata().getClassName(), beanName));
    }

    registry.registerBeanDefinition(beanName, beanDefToRegister);
  }