@Override
  public String[] selectImports(AnnotationMetadata metadata) {
    try {
      AnnotationAttributes attributes =
          AnnotationAttributes.fromMap(
              metadata.getAnnotationAttributes(EnableAutoConfiguration.class.getName(), true));

      Assert.notNull(
          attributes,
          "No auto-configuration attributes found. Is "
              + metadata.getClassName()
              + " annotated with @EnableAutoConfiguration?");

      // Find all possible auto configuration classes, filtering duplicates
      List<String> factories =
          new ArrayList<String>(
              new LinkedHashSet<String>(
                  SpringFactoriesLoader.loadFactoryNames(
                      EnableAutoConfiguration.class, this.beanClassLoader)));

      // Remove those specifically excluded
      Set<String> excluded = new LinkedHashSet<String>();
      excluded.addAll(Arrays.asList(attributes.getStringArray("exclude")));
      excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));
      factories.removeAll(excluded);
      ConditionEvaluationReport.get(this.beanFactory).recordExclusions(excluded);

      // Sort
      factories = new AutoConfigurationSorter(this.resourceLoader).getInPriorityOrder(factories);

      return factories.toArray(new String[factories.size()]);
    } catch (IOException ex) {
      throw new IllegalStateException(ex);
    }
  }
 private void assertMetaAnnotationOverrides(AnnotationMetadata metadata) {
   AnnotationAttributes attributes =
       (AnnotationAttributes)
           metadata.getAnnotationAttributes(TestComponentScan.class.getName(), false);
   String[] basePackages = attributes.getStringArray("basePackages");
   assertThat("length of basePackages[]", basePackages.length, is(1));
   assertThat("basePackages[0]", basePackages[0], is("org.example.componentscan"));
   String[] value = attributes.getStringArray("value");
   assertThat("length of value[]", value.length, is(0));
   Class<?>[] basePackageClasses = attributes.getClassArray("basePackageClasses");
   assertThat("length of basePackageClasses[]", basePackageClasses.length, is(0));
 }
 /**
  * Determine whether the given class does not match any exclude filter and does match at least one
  * include filter.
  *
  * @param metadataReader the ASM ClassReader for the class
  * @return whether the class qualifies as a candidate component
  */
 protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
   for (TypeFilter tf : this.excludeFilters) {
     if (tf.match(metadataReader, this.metadataReaderFactory)) {
       return false;
     }
   }
   for (TypeFilter tf : this.includeFilters) {
     if (tf.match(metadataReader, this.metadataReaderFactory)) {
       AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
       if (!metadata.isAnnotated(Profile.class.getName())) {
         return true;
       }
       AnnotationAttributes profile = MetadataUtils.attributesFor(metadata, Profile.class);
       return this.environment.acceptsProfiles(profile.getStringArray("value"));
     }
   }
   return false;
 }
  @Test
  public void overriddenContextConfigurationLocationsAndInheritLocations() throws Exception {
    Class<?> declaringClass = OverriddenMetaLocationsConfigTestCase.class;
    AnnotationDescriptor<ContextConfiguration> descriptor =
        findAnnotationDescriptor(declaringClass, ContextConfiguration.class);
    assertNotNull(descriptor);
    assertEquals(declaringClass, descriptor.getRootDeclaringClass());
    assertEquals(MetaLocationsConfig.class, descriptor.getComposedAnnotationType());
    assertEquals(ContextConfiguration.class, descriptor.getAnnotationType());
    assertNotNull(descriptor.getComposedAnnotation());
    assertEquals(MetaLocationsConfig.class, descriptor.getComposedAnnotationType());

    // direct access to annotation attributes:
    assertArrayEquals(new String[] {"foo.xml"}, descriptor.getAnnotation().locations());
    assertFalse(descriptor.getAnnotation().inheritLocations());

    // overridden attributes:
    AnnotationAttributes attributes = descriptor.getAnnotationAttributes();
    assertArrayEquals(new String[] {"bar.xml"}, attributes.getStringArray("locations"));
    assertTrue(attributes.getBoolean("inheritLocations"));
  }
 /**
  * Process the given <code>@PropertySource</code> annotation metadata.
  *
  * @param propertySource metadata for the <code>@PropertySource</code> annotation found
  * @throws IOException if loading a property source failed
  */
 private void processPropertySource(AnnotationAttributes propertySource) throws IOException {
   String name = propertySource.getString("name");
   String encoding = propertySource.getString("encoding");
   String[] locations = propertySource.getStringArray("value");
   boolean ignoreResourceNotFound = propertySource.getBoolean("ignoreResourceNotFound");
   Assert.isTrue(locations.length > 0, "At least one @PropertySource(value) location is required");
   for (String location : locations) {
     try {
       String resolvedLocation = this.environment.resolveRequiredPlaceholders(location);
       Resource resource = this.resourceLoader.getResource(resolvedLocation);
       addPropertySource(createPropertySource(name, encoding, resource));
     } catch (IllegalArgumentException ex) {
       // from resolveRequiredPlaceholders
       if (!ignoreResourceNotFound) {
         throw ex;
       }
     } catch (FileNotFoundException ex) {
       // from ResourcePropertySource constructor
       if (!ignoreResourceNotFound) {
         throw ex;
       }
     }
   }
 }
  @Test
  public void overriddenContextConfigurationValue() throws Exception {
    Class<?> declaringClass = OverriddenMetaValueConfigTestCase.class;
    AnnotationDescriptor<ContextConfiguration> descriptor =
        findAnnotationDescriptor(declaringClass, ContextConfiguration.class);
    assertNotNull(descriptor);
    assertEquals(declaringClass, descriptor.getRootDeclaringClass());
    assertEquals(MetaValueConfig.class, descriptor.getComposedAnnotationType());
    assertEquals(ContextConfiguration.class, descriptor.getAnnotationType());
    assertNotNull(descriptor.getComposedAnnotation());
    assertEquals(MetaValueConfig.class, descriptor.getComposedAnnotationType());

    // direct access to annotation value:
    assertArrayEquals(new String[] {"foo.xml"}, descriptor.getAnnotation().value());

    // overridden attribute:
    AnnotationAttributes attributes = descriptor.getAnnotationAttributes();

    // NOTE: we would like to be able to override the 'value' attribute; however,
    // Spring currently does not allow overrides for the 'value' attribute.
    // TODO Determine if Spring should allow overrides for the 'value' attribute in
    // custom annotations.
    assertArrayEquals(new String[] {"foo.xml"}, attributes.getStringArray("value"));
  }
  private void doTestAnnotationInfo(AnnotationMetadata metadata) {
    assertThat(metadata.getClassName(), is(AnnotatedComponent.class.getName()));
    assertThat(metadata.isInterface(), is(false));
    assertThat(metadata.isAnnotation(), is(false));
    assertThat(metadata.isAbstract(), is(false));
    assertThat(metadata.isConcrete(), is(true));
    assertThat(metadata.hasSuperClass(), is(true));
    assertThat(metadata.getSuperClassName(), is(Object.class.getName()));
    assertThat(metadata.getInterfaceNames().length, is(1));
    assertThat(metadata.getInterfaceNames()[0], is(Serializable.class.getName()));

    assertThat(metadata.hasAnnotation(Component.class.getName()), is(true));
    assertThat(metadata.hasAnnotation(Scope.class.getName()), is(true));
    assertThat(metadata.hasAnnotation(SpecialAttr.class.getName()), is(true));
    assertThat(metadata.getAnnotationTypes().size(), is(6));
    assertThat(metadata.getAnnotationTypes().contains(Component.class.getName()), is(true));
    assertThat(metadata.getAnnotationTypes().contains(Scope.class.getName()), is(true));
    assertThat(metadata.getAnnotationTypes().contains(SpecialAttr.class.getName()), is(true));

    AnnotationAttributes compAttrs =
        (AnnotationAttributes) metadata.getAnnotationAttributes(Component.class.getName());
    assertThat(compAttrs.size(), is(1));
    assertThat(compAttrs.getString("value"), is("myName"));
    AnnotationAttributes scopeAttrs =
        (AnnotationAttributes) metadata.getAnnotationAttributes(Scope.class.getName());
    assertThat(scopeAttrs.size(), is(1));
    assertThat(scopeAttrs.getString("value"), is("myScope"));

    Set<MethodMetadata> methods = metadata.getAnnotatedMethods(DirectAnnotation.class.getName());
    MethodMetadata method = methods.iterator().next();
    assertEquals(
        "direct", method.getAnnotationAttributes(DirectAnnotation.class.getName()).get("value"));
    List<Object> allMeta =
        method.getAllAnnotationAttributes(DirectAnnotation.class.getName()).get("value");
    assertThat(
        new HashSet<>(allMeta), is(equalTo(new HashSet<Object>(Arrays.asList("direct", "meta")))));
    allMeta = method.getAllAnnotationAttributes(DirectAnnotation.class.getName()).get("additional");
    assertThat(new HashSet<>(allMeta), is(equalTo(new HashSet<Object>(Arrays.asList("direct")))));

    assertTrue(metadata.isAnnotated(IsAnnotatedAnnotation.class.getName()));

    { // perform tests with classValuesAsString = false (the default)
      AnnotationAttributes specialAttrs =
          (AnnotationAttributes) metadata.getAnnotationAttributes(SpecialAttr.class.getName());
      assertThat(specialAttrs.size(), is(6));
      assertTrue(String.class.isAssignableFrom(specialAttrs.getClass("clazz")));
      assertTrue(specialAttrs.getEnum("state").equals(Thread.State.NEW));

      AnnotationAttributes nestedAnno = specialAttrs.getAnnotation("nestedAnno");
      assertThat("na", is(nestedAnno.getString("value")));
      assertTrue(nestedAnno.getEnum("anEnum").equals(SomeEnum.LABEL1));
      assertArrayEquals(new Class[] {String.class}, (Class[]) nestedAnno.get("classArray"));

      AnnotationAttributes[] nestedAnnoArray = specialAttrs.getAnnotationArray("nestedAnnoArray");
      assertThat(nestedAnnoArray.length, is(2));
      assertThat(nestedAnnoArray[0].getString("value"), is("default"));
      assertTrue(nestedAnnoArray[0].getEnum("anEnum").equals(SomeEnum.DEFAULT));
      assertArrayEquals(new Class[] {Void.class}, (Class[]) nestedAnnoArray[0].get("classArray"));
      assertThat(nestedAnnoArray[1].getString("value"), is("na1"));
      assertTrue(nestedAnnoArray[1].getEnum("anEnum").equals(SomeEnum.LABEL2));
      assertArrayEquals(new Class[] {Number.class}, (Class[]) nestedAnnoArray[1].get("classArray"));
      assertArrayEquals(new Class[] {Number.class}, nestedAnnoArray[1].getClassArray("classArray"));

      AnnotationAttributes optional = specialAttrs.getAnnotation("optional");
      assertThat(optional.getString("value"), is("optional"));
      assertTrue(optional.getEnum("anEnum").equals(SomeEnum.DEFAULT));
      assertArrayEquals(new Class[] {Void.class}, (Class[]) optional.get("classArray"));
      assertArrayEquals(new Class[] {Void.class}, optional.getClassArray("classArray"));

      AnnotationAttributes[] optionalArray = specialAttrs.getAnnotationArray("optionalArray");
      assertThat(optionalArray.length, is(1));
      assertThat(optionalArray[0].getString("value"), is("optional"));
      assertTrue(optionalArray[0].getEnum("anEnum").equals(SomeEnum.DEFAULT));
      assertArrayEquals(new Class[] {Void.class}, (Class[]) optionalArray[0].get("classArray"));
      assertArrayEquals(new Class[] {Void.class}, optionalArray[0].getClassArray("classArray"));

      assertEquals(
          "direct",
          metadata.getAnnotationAttributes(DirectAnnotation.class.getName()).get("value"));
      allMeta = metadata.getAllAnnotationAttributes(DirectAnnotation.class.getName()).get("value");
      assertThat(
          new HashSet<>(allMeta),
          is(equalTo(new HashSet<Object>(Arrays.asList("direct", "meta")))));
      allMeta =
          metadata.getAllAnnotationAttributes(DirectAnnotation.class.getName()).get("additional");
      assertThat(new HashSet<>(allMeta), is(equalTo(new HashSet<Object>(Arrays.asList("direct")))));
    }
    { // perform tests with classValuesAsString = true
      AnnotationAttributes specialAttrs =
          (AnnotationAttributes)
              metadata.getAnnotationAttributes(SpecialAttr.class.getName(), true);
      assertThat(specialAttrs.size(), is(6));
      assertThat(specialAttrs.get("clazz"), is((Object) String.class.getName()));
      assertThat(specialAttrs.getString("clazz"), is(String.class.getName()));

      AnnotationAttributes nestedAnno = specialAttrs.getAnnotation("nestedAnno");
      assertArrayEquals(
          new String[] {String.class.getName()}, nestedAnno.getStringArray("classArray"));
      assertArrayEquals(
          new String[] {String.class.getName()}, nestedAnno.getStringArray("classArray"));

      AnnotationAttributes[] nestedAnnoArray = specialAttrs.getAnnotationArray("nestedAnnoArray");
      assertArrayEquals(
          new String[] {Void.class.getName()}, (String[]) nestedAnnoArray[0].get("classArray"));
      assertArrayEquals(
          new String[] {Void.class.getName()}, nestedAnnoArray[0].getStringArray("classArray"));
      assertArrayEquals(
          new String[] {Number.class.getName()}, (String[]) nestedAnnoArray[1].get("classArray"));
      assertArrayEquals(
          new String[] {Number.class.getName()}, nestedAnnoArray[1].getStringArray("classArray"));

      AnnotationAttributes optional = specialAttrs.getAnnotation("optional");
      assertArrayEquals(new String[] {Void.class.getName()}, (String[]) optional.get("classArray"));
      assertArrayEquals(new String[] {Void.class.getName()}, optional.getStringArray("classArray"));

      AnnotationAttributes[] optionalArray = specialAttrs.getAnnotationArray("optionalArray");
      assertArrayEquals(
          new String[] {Void.class.getName()}, (String[]) optionalArray[0].get("classArray"));
      assertArrayEquals(
          new String[] {Void.class.getName()}, optionalArray[0].getStringArray("classArray"));

      assertEquals(
          metadata.getAnnotationAttributes(DirectAnnotation.class.getName()).get("value"),
          "direct");
      allMeta = metadata.getAllAnnotationAttributes(DirectAnnotation.class.getName()).get("value");
      assertThat(
          new HashSet<>(allMeta),
          is(equalTo(new HashSet<Object>(Arrays.asList("direct", "meta")))));
    }
  }
  /**
   * Read the given {@link BeanMethod}, registering bean definitions with the BeanDefinitionRegistry
   * based on its contents.
   */
  private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
    ConfigurationClass configClass = beanMethod.getConfigurationClass();
    MethodMetadata metadata = beanMethod.getMetadata();
    String methodName = metadata.getMethodName();

    // Do we need to mark the bean as skipped by its condition?
    if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
      configClass.skippedBeanMethods.add(methodName);
      return;
    }
    if (configClass.skippedBeanMethods.contains(methodName)) {
      return;
    }

    // Consider name and any aliases
    AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
    List<String> names = new ArrayList<String>(Arrays.asList(bean.getStringArray("name")));
    String beanName = (names.size() > 0 ? names.remove(0) : methodName);

    // Register aliases even when overridden
    for (String alias : names) {
      this.registry.registerAlias(beanName, alias);
    }

    // Has this effectively been overridden before (e.g. via XML)?
    if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
      return;
    }

    ConfigurationClassBeanDefinition beanDef =
        new ConfigurationClassBeanDefinition(configClass, metadata);
    beanDef.setResource(configClass.getResource());
    beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));

    if (metadata.isStatic()) {
      // static @Bean method
      beanDef.setBeanClassName(configClass.getMetadata().getClassName());
      beanDef.setFactoryMethodName(methodName);
    } else {
      // instance @Bean method
      beanDef.setFactoryBeanName(configClass.getBeanName());
      beanDef.setUniqueFactoryMethodName(methodName);
    }
    beanDef.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
    beanDef.setAttribute(
        RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);

    AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);

    Autowire autowire = bean.getEnum("autowire");
    if (autowire.isAutowire()) {
      beanDef.setAutowireMode(autowire.value());
    }

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

    String destroyMethodName = bean.getString("destroyMethod");
    if (destroyMethodName != null) {
      beanDef.setDestroyMethodName(destroyMethodName);
    }

    // Consider scoping
    ScopedProxyMode proxyMode = ScopedProxyMode.NO;
    // TODO Determine why type is hard coded to org.springframework.context.annotation.Scope,
    // since AnnotationScopeMetadataResolver supports a custom scope annotation type.
    AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(metadata, Scope.class);
    if (attributes != null) {
      beanDef.setScope(
          attributes.getAliasedString("value", Scope.class, configClass.getResource()));
      proxyMode = attributes.getEnum("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 =
          new ConfigurationClassBeanDefinition(
              (RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata);
    }

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

    this.registry.registerBeanDefinition(beanName, beanDefToRegister);
  }