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:
Chris Beams
2012-02-13 15:17:30 +01:00
134 changed files with 3552 additions and 1471 deletions

View File

@@ -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));
}
}
}

View File

@@ -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