Sync with 3.1.x
* 3.1.x: (61 commits) Compensate for changes in JDK 7 Introspector Avoid 'type mismatch' errors in ExtendedBeanInfo Polish ExtendedBeanInfo and tests Infer AnnotationAttributes method return types Minor fix in MVC reference doc chapter Hibernate 4.1 etc TypeDescriptor equals implementation accepts annotations in any order "setBasenames" uses varargs now (for programmatic setup; SPR-9106) @ActiveProfiles mechanism works with @ImportResource as well (SPR-8992 polishing clarified Resource's "getFilename" method to consistently return null substituteNamedParameters detects and unwraps SqlParameterValue object Replace spaces with tabs Consider security in ClassUtils#getMostSpecificMethod Adding null check for username being null. Improvements for registering custom SQL exception translators in app c SPR-7680 Adding QueryTimeoutException to the DataAccessException hiera Minor polish in WebMvcConfigurationSupport Detect overridden boolean getters in ExtendedBeanInfo Polish ExtendedBeanInfoTests ...
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* 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.annotation;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link AnnotationAttributes}.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1.1
|
||||
*/
|
||||
public class AnnotationAttributesTests {
|
||||
|
||||
enum Color { RED, WHITE, BLUE }
|
||||
|
||||
@Test
|
||||
public void testTypeSafeAttributeAccess() {
|
||||
AnnotationAttributes a = new AnnotationAttributes();
|
||||
a.put("name", "dave");
|
||||
a.put("names", new String[] { "dave", "frank", "hal" });
|
||||
a.put("bool1", true);
|
||||
a.put("bool2", false);
|
||||
a.put("color", Color.RED);
|
||||
a.put("clazz", Integer.class);
|
||||
a.put("classes", new Class<?>[] { Number.class, Short.class, Integer.class });
|
||||
a.put("number", 42);
|
||||
a.put("numbers", new int[] { 42, 43 });
|
||||
AnnotationAttributes anno = new AnnotationAttributes();
|
||||
anno.put("value", 10);
|
||||
anno.put("name", "algernon");
|
||||
a.put("anno", anno);
|
||||
a.put("annoArray", new AnnotationAttributes[] { anno });
|
||||
|
||||
assertThat(a.getString("name"), equalTo("dave"));
|
||||
assertThat(a.getStringArray("names"), equalTo(new String[] { "dave", "frank", "hal" }));
|
||||
assertThat(a.getBoolean("bool1"), equalTo(true));
|
||||
assertThat(a.getBoolean("bool2"), equalTo(false));
|
||||
assertThat(a.<Color>getEnum("color"), equalTo(Color.RED));
|
||||
assertTrue(a.getClass("clazz").equals(Integer.class));
|
||||
assertThat(a.getClassArray("classes"), equalTo(new Class[] { Number.class, Short.class, Integer.class }));
|
||||
assertThat(a.<Integer>getNumber("number"), equalTo(42));
|
||||
assertThat(a.getAnnotation("anno").<Integer>getNumber("value"), equalTo(10));
|
||||
assertThat(a.getAnnotationArray("annoArray")[0].getString("name"), equalTo("algernon"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getEnum_emptyAttributeName() {
|
||||
AnnotationAttributes a = new AnnotationAttributes();
|
||||
a.put("color", "RED");
|
||||
try {
|
||||
a.getEnum("");
|
||||
fail();
|
||||
} catch (IllegalArgumentException ex) {
|
||||
assertThat(ex.getMessage(), equalTo("attributeName must not be null or empty"));
|
||||
}
|
||||
try {
|
||||
a.getEnum(null);
|
||||
fail();
|
||||
} catch (IllegalArgumentException ex) {
|
||||
assertThat(ex.getMessage(), equalTo("attributeName must not be null or empty"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getEnum_notFound() {
|
||||
AnnotationAttributes a = new AnnotationAttributes();
|
||||
a.put("color", "RED");
|
||||
try {
|
||||
a.getEnum("colour");
|
||||
fail();
|
||||
} catch (IllegalArgumentException ex) {
|
||||
assertThat(ex.getMessage(), equalTo("Attribute 'colour' not found"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getEnum_typeMismatch() {
|
||||
AnnotationAttributes a = new AnnotationAttributes();
|
||||
a.put("color", "RED");
|
||||
try {
|
||||
a.getEnum("color");
|
||||
fail();
|
||||
} catch (IllegalArgumentException ex) {
|
||||
String expected =
|
||||
"Attribute 'color' is of type [String], but [Enum] was expected";
|
||||
assertThat(ex.getMessage().substring(0, expected.length()), equalTo(expected));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,98 +16,203 @@
|
||||
|
||||
package org.springframework.core.type;
|
||||
|
||||
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;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.type.classreading.MetadataReader;
|
||||
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Unit tests demonstrating that the reflection-based {@link StandardAnnotationMetadata}
|
||||
* and ASM-based {@code AnnotationMetadataReadingVisitor} produce identical output.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
*/
|
||||
public class AnnotationMetadataTests extends TestCase {
|
||||
public class AnnotationMetadataTests {
|
||||
|
||||
@Test
|
||||
public void testStandardAnnotationMetadata() throws IOException {
|
||||
StandardAnnotationMetadata annInfo = new StandardAnnotationMetadata(AnnotatedComponent.class);
|
||||
doTestAnnotationInfo(annInfo);
|
||||
doTestMethodAnnotationInfo(annInfo);
|
||||
AnnotationMetadata metadata = new StandardAnnotationMetadata(AnnotatedComponent.class, true);
|
||||
doTestAnnotationInfo(metadata);
|
||||
doTestMethodAnnotationInfo(metadata);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAsmAnnotationMetadata() throws IOException {
|
||||
MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
|
||||
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(AnnotatedComponent.class.getName());
|
||||
doTestAnnotationInfo(metadataReader.getAnnotationMetadata());
|
||||
doTestMethodAnnotationInfo(metadataReader.getAnnotationMetadata());
|
||||
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));
|
||||
}
|
||||
|
||||
private void doTestAnnotationInfo(AnnotationMetadata metadata) {
|
||||
assertEquals(AnnotatedComponent.class.getName(), metadata.getClassName());
|
||||
assertFalse(metadata.isInterface());
|
||||
assertFalse(metadata.isAbstract());
|
||||
assertTrue(metadata.isConcrete());
|
||||
assertTrue(metadata.hasSuperClass());
|
||||
assertEquals(Object.class.getName(), metadata.getSuperClassName());
|
||||
assertEquals(1, metadata.getInterfaceNames().length);
|
||||
assertEquals(Serializable.class.getName(), metadata.getInterfaceNames()[0]);
|
||||
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()));
|
||||
|
||||
assertTrue(metadata.hasAnnotation(Component.class.getName()));
|
||||
assertTrue(metadata.hasAnnotation(Scope.class.getName()));
|
||||
assertTrue(metadata.hasAnnotation(SpecialAttr.class.getName()));
|
||||
assertEquals(3, metadata.getAnnotationTypes().size());
|
||||
assertTrue(metadata.getAnnotationTypes().contains(Component.class.getName()));
|
||||
assertTrue(metadata.getAnnotationTypes().contains(Scope.class.getName()));
|
||||
assertTrue(metadata.getAnnotationTypes().contains(SpecialAttr.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));
|
||||
|
||||
Map<String, Object> compAttrs = metadata.getAnnotationAttributes(Component.class.getName());
|
||||
assertEquals(1, compAttrs.size());
|
||||
assertEquals("myName", compAttrs.get("value"));
|
||||
Map<String, Object> scopeAttrs = metadata.getAnnotationAttributes(Scope.class.getName());
|
||||
assertEquals(1, scopeAttrs.size());
|
||||
assertEquals("myScope", scopeAttrs.get("value"));
|
||||
Map<String, Object> specialAttrs = metadata.getAnnotationAttributes(SpecialAttr.class.getName());
|
||||
assertEquals(2, specialAttrs.size());
|
||||
assertEquals(String.class, specialAttrs.get("clazz"));
|
||||
assertEquals(Thread.State.NEW, specialAttrs.get("state"));
|
||||
Map<String, Object> specialAttrsString = metadata.getAnnotationAttributes(SpecialAttr.class.getName(), true);
|
||||
assertEquals(String.class.getName(), specialAttrsString .get("clazz"));
|
||||
assertEquals(Thread.State.NEW, specialAttrsString.get("state"));
|
||||
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));
|
||||
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"));
|
||||
}
|
||||
{ // 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"));
|
||||
}
|
||||
}
|
||||
|
||||
private void doTestMethodAnnotationInfo(AnnotationMetadata classMetadata) {
|
||||
Set<MethodMetadata> methods = classMetadata.getAnnotatedMethods(Autowired.class.getName());
|
||||
assertEquals(1, methods.size());
|
||||
assertThat(methods.size(), is(1));
|
||||
for (MethodMetadata methodMetadata : methods) {
|
||||
assertTrue(methodMetadata.isAnnotated(Autowired.class.getName()));
|
||||
assertThat(methodMetadata.isAnnotated(Autowired.class.getName()), is(true));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface SpecialAttr {
|
||||
|
||||
Class clazz();
|
||||
Class<?> clazz();
|
||||
|
||||
Thread.State state();
|
||||
|
||||
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)};
|
||||
}
|
||||
|
||||
|
||||
@Component("myName")
|
||||
@Scope("myScope")
|
||||
@SpecialAttr(clazz = String.class, state = Thread.State.NEW)
|
||||
@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"})
|
||||
private static class AnnotatedComponent implements Serializable {
|
||||
|
||||
@Autowired
|
||||
|
||||
Reference in New Issue
Block a user