/**
  * In order to preserve backward-compatibility, {@link StandardAnnotationMetadata} defaults to
  * return nested annotations and annotation arrays as actual Annotation instances. It is
  * recommended for compatibility with ASM-based AnnotationMetadata implementations to set the
  * 'nestedAnnotationsAsMap' flag to 'true' as is done in the main test above.
  */
 @Test
 public void standardAnnotationMetadata_nestedAnnotationsAsMap_false() throws Exception {
   AnnotationMetadata metadata = new StandardAnnotationMetadata(AnnotatedComponent.class);
   AnnotationAttributes specialAttrs =
       (AnnotationAttributes) metadata.getAnnotationAttributes(SpecialAttr.class.getName());
   Annotation[] nestedAnnoArray = (Annotation[]) specialAttrs.get("nestedAnnoArray");
   assertThat(nestedAnnoArray[0], instanceOf(NestedAnno.class));
 }
  private void assertMultipleAnnotationsWithIdenticalAttributeNames(AnnotationMetadata metadata) {
    AnnotationAttributes attributes1 =
        (AnnotationAttributes)
            metadata.getAnnotationAttributes(NamedAnnotation1.class.getName(), false);
    String name1 = attributes1.getString("name");
    assertThat("name of NamedAnnotation1", name1, is("name 1"));

    AnnotationAttributes attributes2 =
        (AnnotationAttributes)
            metadata.getAnnotationAttributes(NamedAnnotation2.class.getName(), false);
    String name2 = attributes2.getString("name");
    assertThat("name of NamedAnnotation2", name2, is("name 2"));

    AnnotationAttributes attributes3 =
        (AnnotationAttributes)
            metadata.getAnnotationAttributes(NamedAnnotation3.class.getName(), false);
    String name3 = attributes3.getString("name");
    assertThat("name of NamedAnnotation3", name3, is("name 3"));
  }
 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));
 }
 private void doTestSubClassAnnotationInfo(AnnotationMetadata metadata) {
   assertThat(metadata.getClassName(), is(AnnotatedComponentSubClass.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(AnnotatedComponent.class.getName()));
   assertThat(metadata.getInterfaceNames().length, is(0));
   assertThat(metadata.isAnnotated(Component.class.getName()), is(false));
   assertThat(metadata.isAnnotated(Scope.class.getName()), is(false));
   assertThat(metadata.isAnnotated(SpecialAttr.class.getName()), is(false));
   assertThat(metadata.hasAnnotation(Component.class.getName()), is(false));
   assertThat(metadata.hasAnnotation(Scope.class.getName()), is(false));
   assertThat(metadata.hasAnnotation(SpecialAttr.class.getName()), is(false));
   assertThat(metadata.getAnnotationTypes().size(), is(0));
   assertThat(metadata.getAnnotationAttributes(Component.class.getName()), nullValue());
   assertThat(metadata.getAnnotatedMethods(DirectAnnotation.class.getName()).size(), equalTo(0));
   assertThat(metadata.isAnnotated(IsAnnotatedAnnotation.class.getName()), equalTo(false));
   assertThat(metadata.getAllAnnotationAttributes(DirectAnnotation.class.getName()), nullValue());
 }
  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")))));
    }
  }