private AnnotationAttributes assertComponentScanAttributes(Class<?> element, String... expected) {
    AnnotationAttributes attributes = findMergedAnnotationAttributes(element, ComponentScan.class);

    assertNotNull("Should find @ComponentScan on " + element, attributes);
    assertArrayEquals("value: ", expected, attributes.getStringArray("value"));
    assertArrayEquals("basePackages: ", expected, attributes.getStringArray("basePackages"));

    return attributes;
  }
 @Test
 public void findMergedAnnotationAttributesOnClassWithMetaAndLocalTxConfig() {
   AnnotationAttributes attributes =
       findMergedAnnotationAttributes(MetaAndLocalTxConfigClass.class, Transactional.class);
   assertNotNull("Should find @Transactional on MetaAndLocalTxConfigClass", attributes);
   assertEquals(
       "TX qualifier for MetaAndLocalTxConfigClass.",
       "localTxMgr",
       attributes.getString("qualifier"));
 }
 @Test
 public void getMergedAnnotationAttributesOnClassWithLocalAnnotation() {
   Class<?> element = TxConfig.class;
   String name = TX_NAME;
   AnnotationAttributes attributes = getMergedAnnotationAttributes(element, name);
   assertNotNull("Annotation attributes for @Transactional on TxConfig", attributes);
   assertEquals("value for TxConfig.", "TxConfig", attributes.getString("value"));
   // Verify contracts between utility methods:
   assertTrue(isAnnotated(element, name));
 }
  @Test
  public void
      findMergedAnnotationAttributesOnClassWithAttributeAliasInComposedAnnotationAndNestedAnnotationsInTargetAnnotation() {
    AnnotationAttributes attributes =
        assertComponentScanAttributes(TestComponentScanClass.class, "com.example.app.test");

    Filter[] excludeFilters = attributes.getAnnotationArray("excludeFilters", Filter.class);
    assertNotNull(excludeFilters);

    List<String> patterns = stream(excludeFilters).map(Filter::pattern).collect(toList());
    assertEquals(asList("*Test", "*Tests"), patterns);
  }
 @Test
 public void getMergedAnnotationAttributesFavorsLocalComposedAnnotationOverInheritedAnnotation() {
   Class<?> element = SubClassWithInheritedAnnotation.class;
   String name = TX_NAME;
   AnnotationAttributes attributes = getMergedAnnotationAttributes(element, name);
   assertNotNull(
       "AnnotationAttributes for @Transactional on SubClassWithInheritedAnnotation", attributes);
   // Verify contracts between utility methods:
   assertTrue(isAnnotated(element, name));
   assertTrue(
       "readOnly flag for SubClassWithInheritedAnnotation.", attributes.getBoolean("readOnly"));
 }
  @Test
  public void getMergedAnnotationAttributesWithAliasedValueComposedAnnotation() {
    Class<?> element = AliasedValueComposedContextConfigClass.class;
    String name = ContextConfig.class.getName();
    AnnotationAttributes attributes = getMergedAnnotationAttributes(element, name);

    assertNotNull("Should find @ContextConfig on " + element.getSimpleName(), attributes);
    assertArrayEquals("locations", asArray("test.xml"), attributes.getStringArray("locations"));
    assertArrayEquals("value", asArray("test.xml"), attributes.getStringArray("value"));

    // Verify contracts between utility methods:
    assertTrue(isAnnotated(element, name));
  }
  @Test
  public void
      getMergedAnnotationAttributesWithImplicitAliasesInMetaAnnotationOnComposedAnnotation() {
    Class<?> element = ComposedImplicitAliasesContextConfigClass.class;
    String name = ImplicitAliasesContextConfig.class.getName();
    AnnotationAttributes attributes = getMergedAnnotationAttributes(element, name);
    String[] expected = asArray("A.xml", "B.xml");

    assertNotNull(
        "Should find @ImplicitAliasesContextConfig on " + element.getSimpleName(), attributes);
    assertArrayEquals("groovyScripts", expected, attributes.getStringArray("groovyScripts"));
    assertArrayEquals("xmlFiles", expected, attributes.getStringArray("xmlFiles"));
    assertArrayEquals("locations", expected, attributes.getStringArray("locations"));
    assertArrayEquals("value", expected, attributes.getStringArray("value"));

    // Verify contracts between utility methods:
    assertTrue(isAnnotated(element, name));
  }
  private void getMergedAnnotationAttributesWithHalfConventionBasedAndHalfAliasedComposedAnnotation(
      Class<?> clazz) {
    String[] expected = asArray("explicitDeclaration");
    String name = ContextConfig.class.getName();
    String simpleName = clazz.getSimpleName();
    AnnotationAttributes attributes = getMergedAnnotationAttributes(clazz, name);

    assertNotNull("Should find @ContextConfig on " + simpleName, attributes);
    assertArrayEquals(
        "locations for class [" + clazz.getSimpleName() + "]",
        expected,
        attributes.getStringArray("locations"));
    assertArrayEquals(
        "value for class [" + clazz.getSimpleName() + "]",
        expected,
        attributes.getStringArray("value"));

    // Verify contracts between utility methods:
    assertTrue(isAnnotated(clazz, name));
  }
  @Test
  public void findAndSynthesizeAnnotationAttributesOnClassWithAttributeAliasesInTargetAnnotation() {
    String qualifier = "aliasForQualifier";

    // 1) Find and merge AnnotationAttributes from the annotation hierarchy
    AnnotationAttributes attributes =
        findMergedAnnotationAttributes(
            AliasedTransactionalComponentClass.class, AliasedTransactional.class);
    assertNotNull("@AliasedTransactional on AliasedTransactionalComponentClass.", attributes);

    // 2) Synthesize the AnnotationAttributes back into the target annotation
    AliasedTransactional annotation =
        AnnotationUtils.synthesizeAnnotation(
            attributes, AliasedTransactional.class, AliasedTransactionalComponentClass.class);
    assertNotNull(annotation);

    // 3) Verify that the AnnotationAttributes and synthesized annotation are equivalent
    assertEquals("TX value via attributes.", qualifier, attributes.getString("value"));
    assertEquals("TX value via synthesized annotation.", qualifier, annotation.value());
    assertEquals("TX qualifier via attributes.", qualifier, attributes.getString("qualifier"));
    assertEquals("TX qualifier via synthesized annotation.", qualifier, annotation.qualifier());
  }