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

19 20 21 22 23 24
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;

A
Arjen Poutsma 已提交
25 26
import java.io.IOException;
import java.io.Serializable;
27
import java.lang.annotation.Annotation;
28 29 30 31
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
32
import java.util.Set;
A
Arjen Poutsma 已提交
33

34
import org.junit.Test;
35

36 37
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
38
import org.springframework.core.annotation.AnnotationAttributes;
A
Arjen Poutsma 已提交
39
import org.springframework.core.type.classreading.MetadataReader;
40
import org.springframework.core.type.classreading.MetadataReaderFactory;
A
Arjen Poutsma 已提交
41 42 43 44
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
import org.springframework.stereotype.Component;

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

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

60
	@Test
A
Arjen Poutsma 已提交
61 62 63
	public void testAsmAnnotationMetadata() throws IOException {
		MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
		MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(AnnotatedComponent.class.getName());
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
		AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
		doTestAnnotationInfo(metadata);
		doTestMethodAnnotationInfo(metadata);
	}

	/**
	 * 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 testStandardAnnotationMetadata_nestedAnnotationsAsMap_false() throws IOException {
		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));
A
Arjen Poutsma 已提交
83 84 85
	}

	private void doTestAnnotationInfo(AnnotationMetadata metadata) {
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
		assertThat(metadata.getClassName(), is(AnnotatedComponent.class.getName()));
		assertThat(metadata.isInterface(), 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(3));
		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"));
		{ // perform tests with classValuesAsString = false (the default)
			AnnotationAttributes specialAttrs = (AnnotationAttributes) metadata.getAnnotationAttributes(SpecialAttr.class.getName());
			assertThat(specialAttrs.size(), is(6));
112 113
			assertTrue(String.class.isAssignableFrom(specialAttrs.getClass("clazz")));
			assertTrue(specialAttrs.getEnum("state").equals(Thread.State.NEW));
114 115 116

			AnnotationAttributes nestedAnno = specialAttrs.getAnnotation("nestedAnno");
			assertThat("na", is(nestedAnno.getString("value")));
117
			assertTrue(nestedAnno.getEnum("anEnum").equals(SomeEnum.LABEL1));
118 119 120 121 122
			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"));
123
			assertTrue(nestedAnnoArray[0].getEnum("anEnum").equals(SomeEnum.DEFAULT));
124 125
			assertArrayEquals(new Class[]{Void.class}, (Class[])nestedAnnoArray[0].get("classArray"));
			assertThat(nestedAnnoArray[1].getString("value"), is("na1"));
126
			assertTrue(nestedAnnoArray[1].getEnum("anEnum").equals(SomeEnum.LABEL2));
127 128 129 130 131
			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"));
132
			assertTrue(optional.getEnum("anEnum").equals(SomeEnum.DEFAULT));
133 134 135 136 137 138
			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"));
139
			assertTrue(optionalArray[0].getEnum("anEnum").equals(SomeEnum.DEFAULT));
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
			assertArrayEquals(new Class[]{Void.class}, (Class[])optionalArray[0].get("classArray"));
			assertArrayEquals(new Class[]{Void.class}, optionalArray[0].getClassArray("classArray"));
		}
		{ // 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()}, (String[])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"));
		}
167
	}
J
Juergen Hoeller 已提交
168

169
	private void doTestMethodAnnotationInfo(AnnotationMetadata classMetadata) {
170
		Set<MethodMetadata> methods = classMetadata.getAnnotatedMethods(Autowired.class.getName());
171
		assertThat(methods.size(), is(1));
172
		for (MethodMetadata methodMetadata : methods) {
173
			assertThat(methodMetadata.isAnnotated(Autowired.class.getName()), is(true));
174 175
		}
	}
176

177 178 179 180 181 182 183 184 185 186 187
	public static enum SomeEnum {
		LABEL1, LABEL2, DEFAULT;
	}

	@Target({})
	@Retention(RetentionPolicy.RUNTIME)
	public @interface NestedAnno {
		String value() default "default";
		SomeEnum anEnum() default SomeEnum.DEFAULT;
		Class<?>[] classArray() default Void.class;
	}
188 189 190 191 192

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

193
		Class<?> clazz();
A
Arjen Poutsma 已提交
194

195
		Thread.State state();
196 197 198 199 200 201 202 203

		NestedAnno nestedAnno();

		NestedAnno[] nestedAnnoArray();

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

		NestedAnno[] optionalArray() default {@NestedAnno(value="optional", anEnum=SomeEnum.DEFAULT, classArray=Void.class)};
A
Arjen Poutsma 已提交
204 205 206 207 208
	}


	@Component("myName")
	@Scope("myScope")
209 210 211 212 213 214 215
	@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"})
A
Arjen Poutsma 已提交
216
	private static class AnnotatedComponent implements Serializable {
217 218 219 220
		
		@Autowired
		public void doWork(@Qualifier("myColor") java.awt.Color color) {
		}
J
Juergen Hoeller 已提交
221 222

		public void doSleep()  {
223
		}
A
Arjen Poutsma 已提交
224 225 226
	}

}