AnnotationMetadataTests.java 23.9 KB
Newer Older
A
Arjen Poutsma 已提交
1
/*
2
 * Copyright 2002-2016 the original author or authors.
A
Arjen Poutsma 已提交
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 * 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.core.type;

import java.io.Serializable;
20
import java.lang.annotation.Annotation;
21
import java.lang.annotation.Documented;
22 23 24 25
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
26 27 28
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
29
import java.util.Set;
A
Arjen Poutsma 已提交
30

31
import org.junit.Test;
32

33
import org.springframework.core.annotation.AliasFor;
34
import org.springframework.core.annotation.AnnotationAttributes;
A
Arjen Poutsma 已提交
35
import org.springframework.core.type.classreading.MetadataReader;
36
import org.springframework.core.type.classreading.MetadataReaderFactory;
A
Arjen Poutsma 已提交
37 38 39
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
import org.springframework.stereotype.Component;

40 41 42
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;

A
Arjen Poutsma 已提交
43
/**
44 45 46
 * Unit tests demonstrating that the reflection-based {@link StandardAnnotationMetadata}
 * and ASM-based {@code AnnotationMetadataReadingVisitor} produce identical output.
 *
A
Arjen Poutsma 已提交
47
 * @author Juergen Hoeller
48
 * @author Chris Beams
49
 * @author Phillip Webb
50
 * @author Sam Brannen
A
Arjen Poutsma 已提交
51
 */
52
public class AnnotationMetadataTests {
A
Arjen Poutsma 已提交
53

54
	@Test
55
	public void standardAnnotationMetadata() throws Exception {
56 57 58
		AnnotationMetadata metadata = new StandardAnnotationMetadata(AnnotatedComponent.class, true);
		doTestAnnotationInfo(metadata);
		doTestMethodAnnotationInfo(metadata);
A
Arjen Poutsma 已提交
59 60
	}

61
	@Test
62
	public void asmAnnotationMetadata() throws Exception {
A
Arjen Poutsma 已提交
63 64
		MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
		MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(AnnotatedComponent.class.getName());
65 66 67 68 69
		AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
		doTestAnnotationInfo(metadata);
		doTestMethodAnnotationInfo(metadata);
	}

70 71 72 73 74 75 76 77 78 79 80 81 82 83
	@Test
	public void standardAnnotationMetadataForSubclass() throws Exception {
		AnnotationMetadata metadata = new StandardAnnotationMetadata(AnnotatedComponentSubClass.class, true);
		doTestSubClassAnnotationInfo(metadata);
	}

	@Test
	public void asmAnnotationMetadataForSubclass() throws Exception {
		MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
		MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(AnnotatedComponentSubClass.class.getName());
		AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
		doTestSubClassAnnotationInfo(metadata);
	}

84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
	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());
	}

	@Test
	public void standardAnnotationMetadataForInterface() throws Exception {
		AnnotationMetadata metadata = new StandardAnnotationMetadata(AnnotationMetadata.class, true);
		doTestMetadataForInterfaceClass(metadata);
	}

	@Test
	public void asmAnnotationMetadataForInterface() throws Exception {
		MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
		MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(AnnotationMetadata.class.getName());
		AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
		doTestMetadataForInterfaceClass(metadata);
	}

	private void doTestMetadataForInterfaceClass(AnnotationMetadata metadata) {
		assertThat(metadata.getClassName(), is(AnnotationMetadata.class.getName()));
		assertThat(metadata.isInterface(), is(true));
		assertThat(metadata.isAnnotation(), is(false));
		assertThat(metadata.isAbstract(), is(true));
		assertThat(metadata.isConcrete(), is(false));
		assertThat(metadata.hasSuperClass(), is(false));
		assertThat(metadata.getSuperClassName(), nullValue());
		assertThat(metadata.getInterfaceNames().length, is(2));
		assertThat(metadata.getInterfaceNames()[0], is(ClassMetadata.class.getName()));
		assertThat(metadata.getInterfaceNames()[1], is(AnnotatedTypeMetadata.class.getName()));
		assertThat(metadata.getAnnotationTypes().size(), is(0));
	}

	@Test
	public void standardAnnotationMetadataForAnnotation() throws Exception {
		AnnotationMetadata metadata = new StandardAnnotationMetadata(Component.class, true);
		doTestMetadataForAnnotationClass(metadata);
	}

	@Test
	public void asmAnnotationMetadataForAnnotation() throws Exception {
		MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
		MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(Component.class.getName());
		AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
		doTestMetadataForAnnotationClass(metadata);
	}

	private void doTestMetadataForAnnotationClass(AnnotationMetadata metadata) {
		assertThat(metadata.getClassName(), is(Component.class.getName()));
		assertThat(metadata.isInterface(), is(true));
		assertThat(metadata.isAnnotation(), is(true));
		assertThat(metadata.isAbstract(), is(true));
		assertThat(metadata.isConcrete(), is(false));
		assertThat(metadata.hasSuperClass(), is(false));
		assertThat(metadata.getSuperClassName(), nullValue());
		assertThat(metadata.getInterfaceNames().length, is(1));
		assertThat(metadata.getInterfaceNames()[0], is(Annotation.class.getName()));
158
		assertThat(metadata.isAnnotated(Documented.class.getName()), is(false));
159 160 161 162 163 164 165 166
		assertThat(metadata.isAnnotated(Scope.class.getName()), is(false));
		assertThat(metadata.isAnnotated(SpecialAttr.class.getName()), is(false));
		assertThat(metadata.hasAnnotation(Documented.class.getName()), is(true));
		assertThat(metadata.hasAnnotation(Scope.class.getName()), is(false));
		assertThat(metadata.hasAnnotation(SpecialAttr.class.getName()), is(false));
		assertThat(metadata.getAnnotationTypes().size(), is(3));
	}

167 168 169 170 171 172 173 174
	/**
	 * 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
175
	public void standardAnnotationMetadata_nestedAnnotationsAsMap_false() throws Exception {
176 177
		AnnotationMetadata metadata = new StandardAnnotationMetadata(AnnotatedComponent.class);
		AnnotationAttributes specialAttrs = (AnnotationAttributes) metadata.getAnnotationAttributes(SpecialAttr.class.getName());
178
		Annotation[] nestedAnnoArray = (Annotation[]) specialAttrs.get("nestedAnnoArray");
179
		assertThat(nestedAnnoArray[0], instanceOf(NestedAnno.class));
A
Arjen Poutsma 已提交
180 181
	}

182 183
	@Test
	public void metaAnnotationOverridesUsingStandardAnnotationMetadata() {
184
		AnnotationMetadata metadata = new StandardAnnotationMetadata(ComposedConfigurationWithAttributeOverridesClass.class);
185 186 187 188 189 190 191 192 193 194 195 196 197
		assertMetaAnnotationOverrides(metadata);
	}

	@Test
	public void metaAnnotationOverridesUsingAnnotationMetadataReadingVisitor() throws Exception {
		MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
		MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(ComposedConfigurationWithAttributeOverridesClass.class.getName());
		AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
		assertMetaAnnotationOverrides(metadata);
	}

	private void assertMetaAnnotationOverrides(AnnotationMetadata metadata) {
		AnnotationAttributes attributes = (AnnotationAttributes) metadata.getAnnotationAttributes(
J
Juergen Hoeller 已提交
198
				TestComponentScan.class.getName(), false);
199 200 201 202 203 204 205 206 207
		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));
	}

208
	/**
209
	 * https://jira.spring.io/browse/SPR-11649
210
	 */
211 212 213 214 215
	@Test
	public void multipleAnnotationsWithIdenticalAttributeNamesUsingStandardAnnotationMetadata() {
		AnnotationMetadata metadata = new StandardAnnotationMetadata(NamedAnnotationsClass.class);
		assertMultipleAnnotationsWithIdenticalAttributeNames(metadata);
	}
216

217 218 219 220 221 222 223 224 225 226
	/**
	 * https://jira.spring.io/browse/SPR-11649
	 */
	@Test
	public void multipleAnnotationsWithIdenticalAttributeNamesUsingAnnotationMetadataReadingVisitor() throws Exception {
		MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
		MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(NamedAnnotationsClass.class.getName());
		AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
		assertMultipleAnnotationsWithIdenticalAttributeNames(metadata);
	}
227

228 229 230 231 232 233 234 235
	/**
	 * https://jira.spring.io/browse/SPR-11649
	 */
	@Test
	public void composedAnnotationWithMetaAnnotationsWithIdenticalAttributeNamesUsingStandardAnnotationMetadata() {
		AnnotationMetadata metadata = new StandardAnnotationMetadata(NamedComposedAnnotationClass.class);
		assertMultipleAnnotationsWithIdenticalAttributeNames(metadata);
	}
236

237 238 239 240 241 242 243 244 245 246 247
	/**
	 * https://jira.spring.io/browse/SPR-11649
	 */
	@Test
	public void composedAnnotationWithMetaAnnotationsWithIdenticalAttributeNamesUsingAnnotationMetadataReadingVisitor() throws Exception {
		MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
		MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(NamedComposedAnnotationClass.class.getName());
		AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
		assertMultipleAnnotationsWithIdenticalAttributeNames(metadata);
	}

248

249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
	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"));
264 265
	}

A
Arjen Poutsma 已提交
266
	private void doTestAnnotationInfo(AnnotationMetadata metadata) {
267 268
		assertThat(metadata.getClassName(), is(AnnotatedComponent.class.getName()));
		assertThat(metadata.isInterface(), is(false));
269
		assertThat(metadata.isAnnotation(), is(false));
270 271 272 273 274 275 276 277 278 279
		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));
280
		assertThat(metadata.getAnnotationTypes().size(), is(6));
281 282 283 284 285 286 287 288 289 290
		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"));
291 292 293 294

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

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

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

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

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

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

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

			assertEquals("direct", metadata.getAnnotationAttributes(DirectAnnotation.class.getName()).get("value"));
			allMeta = metadata.getAllAnnotationAttributes(DirectAnnotation.class.getName()).get("value");
339
			assertThat(new HashSet<>(allMeta), is(equalTo(new HashSet<Object>(Arrays.asList("direct", "meta")))));
340
			allMeta = metadata.getAllAnnotationAttributes(DirectAnnotation.class.getName()).get("additional");
341
			assertThat(new HashSet<>(allMeta), is(equalTo(new HashSet<Object>(Arrays.asList("direct")))));
342 343
		}
		{ // perform tests with classValuesAsString = true
344 345
			AnnotationAttributes specialAttrs = (AnnotationAttributes) metadata.getAnnotationAttributes(
				SpecialAttr.class.getName(), true);
346
			assertThat(specialAttrs.size(), is(6));
347
			assertThat(specialAttrs.get("clazz"), is((Object) String.class.getName()));
348 349 350
			assertThat(specialAttrs.getString("clazz"), is(String.class.getName()));

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

			AnnotationAttributes[] nestedAnnoArray = specialAttrs.getAnnotationArray("nestedAnnoArray");
355 356 357 358
			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"));
359 360

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

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

			assertEquals(metadata.getAnnotationAttributes(DirectAnnotation.class.getName()).get("value"), "direct");
			allMeta = metadata.getAllAnnotationAttributes(DirectAnnotation.class.getName()).get("value");
370
			assertThat(new HashSet<>(allMeta), is(equalTo(new HashSet<Object>(Arrays.asList("direct", "meta")))));
371
		}
372
	}
J
Juergen Hoeller 已提交
373

374
	private void doTestMethodAnnotationInfo(AnnotationMetadata classMetadata) {
375
		Set<MethodMetadata> methods = classMetadata.getAnnotatedMethods(TestAutowired.class.getName());
376
		assertThat(methods.size(), is(1));
377
		for (MethodMetadata methodMetadata : methods) {
378
			assertThat(methodMetadata.isAnnotated(TestAutowired.class.getName()), is(true));
379 380
		}
	}
381

382 383 384

	// -------------------------------------------------------------------------

385
	public static enum SomeEnum {
386
		LABEL1, LABEL2, DEFAULT
387 388 389 390 391
	}

	@Target({})
	@Retention(RetentionPolicy.RUNTIME)
	public @interface NestedAnno {
392

393
		String value() default "default";
394

395
		SomeEnum anEnum() default SomeEnum.DEFAULT;
396

397 398
		Class<?>[] classArray() default Void.class;
	}
399 400 401 402 403

	@Target(ElementType.TYPE)
	@Retention(RetentionPolicy.RUNTIME)
	public @interface SpecialAttr {

404
		Class<?> clazz();
A
Arjen Poutsma 已提交
405

406
		Thread.State state();
407 408 409 410 411

		NestedAnno nestedAnno();

		NestedAnno[] nestedAnnoArray();

412
		NestedAnno optional() default @NestedAnno(value = "optional", anEnum = SomeEnum.DEFAULT, classArray = Void.class);
413

414
		NestedAnno[] optionalArray() default { @NestedAnno(value = "optional", anEnum = SomeEnum.DEFAULT, classArray = Void.class) };
A
Arjen Poutsma 已提交
415 416
	}

417
	@Target({ElementType.TYPE, ElementType.METHOD})
418 419
	@Retention(RetentionPolicy.RUNTIME)
	public @interface DirectAnnotation {
420

421 422 423 424 425
		@AliasFor("myValue")
		String value() default "";

		@AliasFor("value")
		String myValue() default "";
426 427

		String additional() default "direct";
428 429
	}

430
	@Target(ElementType.TYPE)
431 432 433 434 435 436 437 438 439
	@Retention(RetentionPolicy.RUNTIME)
	public @interface IsAnnotatedAnnotation {
	}

	@Target(ElementType.TYPE)
	@Retention(RetentionPolicy.RUNTIME)
	@DirectAnnotation("meta")
	@IsAnnotatedAnnotation
	public @interface MetaAnnotation {
440 441

		String additional() default "meta";
442 443
	}

444
	@Target({ElementType.TYPE, ElementType.METHOD})
445 446 447 448
	@Retention(RetentionPolicy.RUNTIME)
	@MetaAnnotation
	public @interface MetaMetaAnnotation {
	}
A
Arjen Poutsma 已提交
449

450 451 452
	@Target(ElementType.TYPE)
	@Retention(RetentionPolicy.RUNTIME)
	public @interface EnumSubclasses {
453

454 455 456 457
		SubclassEnum[] value();
	}

	// SPR-10914
458
	public enum SubclassEnum {
459
		FOO {
460
		/* Do not delete! This subclassing is intentional. */
461 462
		},
		BAR {
463
		/* Do not delete! This subclassing is intentional. */
464
		}
465 466
	}

A
Arjen Poutsma 已提交
467 468
	@Component("myName")
	@Scope("myScope")
469 470 471 472
	@SpecialAttr(clazz = String.class, state = Thread.State.NEW,
			nestedAnno = @NestedAnno(value = "na", anEnum = SomeEnum.LABEL1, classArray = {String.class}),
			nestedAnnoArray = {@NestedAnno, @NestedAnno(value = "na1", anEnum = SomeEnum.LABEL2, classArray = {Number.class})})
	@SuppressWarnings({"serial", "unused"})
473 474
	@DirectAnnotation("direct")
	@MetaMetaAnnotation
475
	@EnumSubclasses({SubclassEnum.FOO, SubclassEnum.BAR})
A
Arjen Poutsma 已提交
476
	private static class AnnotatedComponent implements Serializable {
477

478 479
		@TestAutowired
		public void doWork(@TestQualifier("myColor") java.awt.Color color) {
480
		}
J
Juergen Hoeller 已提交
481

482
		public void doSleep() {
483
		}
484 485 486 487 488

		@DirectAnnotation("direct")
		@MetaMetaAnnotation
		public void meta() {
		}
A
Arjen Poutsma 已提交
489 490
	}

491
	@SuppressWarnings("serial")
492 493 494
	private static class AnnotatedComponentSubClass extends AnnotatedComponent {
	}

495 496 497
	@Target(ElementType.TYPE)
	@Retention(RetentionPolicy.RUNTIME)
	@Component
498
	public @interface TestConfiguration {
499 500 501 502 503 504

		String value() default "";
	}

	@Retention(RetentionPolicy.RUNTIME)
	@Target(ElementType.TYPE)
505
	public @interface TestComponentScan {
506 507 508 509 510 511 512 513 514 515 516 517

		String[] value() default {};

		String[] basePackages() default {};

		Class<?>[] basePackageClasses() default {};
	}

	@TestConfiguration
	@TestComponentScan(basePackages = "bogus")
	@Retention(RetentionPolicy.RUNTIME)
	@Target(ElementType.TYPE)
518
	public @interface ComposedConfigurationWithAttributeOverrides {
519 520 521 522 523 524 525 526

		String[] basePackages() default {};
	}

	@ComposedConfigurationWithAttributeOverrides(basePackages = "org.example.componentscan")
	public static class ComposedConfigurationWithAttributeOverridesClass {
	}

527 528
	@Retention(RetentionPolicy.RUNTIME)
	@Target(ElementType.TYPE)
529
	public @interface NamedAnnotation1 {
530 531 532 533 534
		String name() default "";
	}

	@Retention(RetentionPolicy.RUNTIME)
	@Target(ElementType.TYPE)
535
	public @interface NamedAnnotation2 {
536 537 538 539 540
		String name() default "";
	}

	@Retention(RetentionPolicy.RUNTIME)
	@Target(ElementType.TYPE)
541
	public @interface NamedAnnotation3 {
542 543 544 545 546 547 548 549 550 551 552 553 554 555
		String name() default "";
	}

	@NamedAnnotation1(name = "name 1")
	@NamedAnnotation2(name = "name 2")
	@NamedAnnotation3(name = "name 3")
	public static class NamedAnnotationsClass {
	}

	@NamedAnnotation1(name = "name 1")
	@NamedAnnotation2(name = "name 2")
	@NamedAnnotation3(name = "name 3")
	@Retention(RetentionPolicy.RUNTIME)
	@Target(ElementType.TYPE)
556
	public @interface NamedComposedAnnotation {
557 558 559 560 561 562
	}

	@NamedComposedAnnotation
	public static class NamedComposedAnnotationClass {
	}

A
Arjen Poutsma 已提交
563
}