Package org.springframework.context.annotation

Source Code of org.springframework.context.annotation.AnnotationBeanNameGenerator

/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.context.annotation;

import java.beans.Introspector;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;

/**
* {@link org.springframework.beans.factory.support.BeanNameGenerator}
* implementation for bean classes annotated with the
* {@link org.springframework.stereotype.Component @Component} annotation
* or with another annotation that is itself annotated with
* {@link org.springframework.stereotype.Component @Component} as a
* meta-annotation. For example, Spring's stereotype annotations (such as
* {@link org.springframework.stereotype.Repository @Repository}) are
* themselves annotated with
* {@link org.springframework.stereotype.Component @Component}.
*
* <p>Also supports Java EE 6's {@link javax.annotation.ManagedBean} and
* JSR-330's {@link javax.inject.Named} annotations, if available. Note that
* Spring component annotations always override such standard annotations.
*
* <p>If the annotation's value doesn't indicate a bean name, an appropriate
* name will be built based on the short name of the class (with the first
* letter lower-cased). For example:
*
* <pre class="code">com.xyz.FooServiceImpl -&gt; fooServiceImpl</pre>
*
* @author Juergen Hoeller
* @author Mark Fisher
* @since 2.5
* @see org.springframework.stereotype.Component#value()
* @see org.springframework.stereotype.Repository#value()
* @see org.springframework.stereotype.Service#value()
* @see org.springframework.stereotype.Controller#value()
* @see javax.inject.Named#value()
*/
public class AnnotationBeanNameGenerator implements BeanNameGenerator {

  private static final String COMPONENT_ANNOTATION_CLASSNAME = "org.springframework.stereotype.Component";


  public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
    if (definition instanceof AnnotatedBeanDefinition) {
      String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
      if (StringUtils.hasText(beanName)) {
        // Explicit bean name found.
        return beanName;
      }
    }
    // Fallback: generate a unique default bean name.
    return buildDefaultBeanName(definition, registry);
  }

  /**
   * Derive a bean name from one of the annotations on the class.
   * @param annotatedDef the annotation-aware bean definition
   * @return the bean name, or <code>null</code> if none is found
   */
  protected String determineBeanNameFromAnnotation(AnnotatedBeanDefinition annotatedDef) {
    AnnotationMetadata amd = annotatedDef.getMetadata();
    Set<String> types = amd.getAnnotationTypes();
    String beanName = null;
    for (String type : types) {
      AnnotationAttributes attributes = MetadataUtils.attributesFor(amd, type);
      if (isStereotypeWithNameValue(type, amd.getMetaAnnotationTypes(type), attributes)) {
        String value = (String) attributes.get("value");
        if (StringUtils.hasLength(value)) {
          if (beanName != null && !value.equals(beanName)) {
            throw new IllegalStateException("Stereotype annotations suggest inconsistent " +
                "component names: '" + beanName + "' versus '" + value + "'");
          }
          beanName = value;
        }
      }
    }
    return beanName;
  }

  /**
   * Check whether the given annotation is a stereotype that is allowed
   * to suggest a component name through its annotation <code>value()</code>.
   * @param annotationType the name of the annotation class to check
   * @param metaAnnotationTypes the names of meta-annotations on the given annotation
   * @param attributes the map of attributes for the given annotation
   * @return whether the annotation qualifies as a stereotype with component name
   */
  protected boolean isStereotypeWithNameValue(String annotationType,
      Set<String> metaAnnotationTypes, Map<String, Object> attributes) {

    boolean isStereotype = annotationType.equals(COMPONENT_ANNOTATION_CLASSNAME) ||
        (metaAnnotationTypes != null && metaAnnotationTypes.contains(COMPONENT_ANNOTATION_CLASSNAME)) ||
        annotationType.equals("javax.annotation.ManagedBean") ||
        annotationType.equals("javax.inject.Named");
    return (isStereotype && attributes != null && attributes.containsKey("value"));
  }

  /**
   * Derive a default bean name from the given bean definition.
   * <p>The default implementation delegates to {@link #buildDefaultBeanName(BeanDefinition)}.
   * @param definition the bean definition to build a bean name for
   * @param registry the registry that the given bean definition is being registered with
   * @return the default bean name (never <code>null</code>)
   */
  protected String buildDefaultBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
    return buildDefaultBeanName(definition);
  }

  /**
   * Derive a default bean name from the given bean definition.
   * <p>The default implementation simply builds a decapitalized version
   * of the short class name: e.g. "mypackage.MyJdbcDao" -> "myJdbcDao".
   * <p>Note that inner classes will thus have names of the form
   * "outerClassName.innerClassName", which because of the period in the
   * name may be an issue if you are autowiring by name.
   * @param definition the bean definition to build a bean name for
   * @return the default bean name (never <code>null</code>)
   */
  protected String buildDefaultBeanName(BeanDefinition definition) {
    String shortClassName = ClassUtils.getShortName(definition.getBeanClassName());
    return Introspector.decapitalize(shortClassName);
  }

}
TOP

Related Classes of org.springframework.context.annotation.AnnotationBeanNameGenerator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.