summaryrefslogtreecommitdiff
path: root/spring-core/src/test/java
diff options
context:
space:
mode:
Diffstat (limited to 'spring-core/src/test/java')
-rw-r--r--spring-core/src/test/java/org/springframework/core/GenericTypeResolverTests.java2
-rw-r--r--spring-core/src/test/java/org/springframework/core/SerializableTypeWrapperTests.java52
-rw-r--r--spring-core/src/test/java/org/springframework/core/annotation/AnnotatedElementUtilsTests.java247
-rw-r--r--spring-core/src/test/java/org/springframework/core/annotation/AnnotationAttributesTests.java366
-rw-r--r--spring-core/src/test/java/org/springframework/core/annotation/AnnotationUtilsTests.java307
-rw-r--r--spring-core/src/test/java/org/springframework/core/annotation/ComposedRepeatableAnnotationsTests.java386
-rw-r--r--spring-core/src/test/java/org/springframework/core/annotation/MapAnnotationAttributeExtractorTests.java36
-rw-r--r--spring-core/src/test/java/org/springframework/core/annotation/MultipleComposedAnnotationsOnSingleAnnotatedElementTests.java368
-rw-r--r--spring-core/src/test/java/org/springframework/core/convert/TypeDescriptorTests.java574
-rw-r--r--spring-core/src/test/java/org/springframework/core/convert/support/CollectionToCollectionConverterTests.java48
-rw-r--r--spring-core/src/test/java/org/springframework/core/convert/support/DefaultConversionServiceTests.java65
-rw-r--r--spring-core/src/test/java/org/springframework/core/convert/support/GenericConversionServiceTests.java121
-rw-r--r--spring-core/src/test/java/org/springframework/core/convert/support/MapToMapConverterTests.java66
-rw-r--r--spring-core/src/test/java/org/springframework/core/convert/support/StreamConverterTests.java21
-rw-r--r--spring-core/src/test/java/org/springframework/core/env/DummyEnvironment.java9
-rw-r--r--spring-core/src/test/java/org/springframework/core/env/PropertySourceTests.java20
-rw-r--r--spring-core/src/test/java/org/springframework/core/env/PropertySourcesPropertyResolverTests.java23
-rw-r--r--spring-core/src/test/java/org/springframework/core/env/SystemEnvironmentPropertySourceTests.java55
-rw-r--r--spring-core/src/test/java/org/springframework/core/io/support/DummyPackagePrivateFactory.java (renamed from spring-core/src/test/java/org/springframework/tests/BuildTests.java)22
-rw-r--r--spring-core/src/test/java/org/springframework/core/io/support/ResourceRegionTests.java47
-rw-r--r--spring-core/src/test/java/org/springframework/core/io/support/SpringFactoriesLoaderTests.java56
-rw-r--r--spring-core/src/test/java/org/springframework/core/type/AnnotationMetadataTests.java24
-rw-r--r--spring-core/src/test/java/org/springframework/core/type/classreading/ClassMetadataReadingVisitorMemberClassTests.java3
-rw-r--r--spring-core/src/test/java/org/springframework/tests/Assume.java58
-rw-r--r--spring-core/src/test/java/org/springframework/tests/JavaVersion.java95
-rw-r--r--spring-core/src/test/java/org/springframework/tests/JavaVersionTests.java43
-rw-r--r--spring-core/src/test/java/org/springframework/tests/TestGroup.java11
-rw-r--r--spring-core/src/test/java/org/springframework/tests/TestGroupTests.java8
-rw-r--r--spring-core/src/test/java/org/springframework/util/AntPathMatcherTests.java55
-rw-r--r--spring-core/src/test/java/org/springframework/util/AutoPopulatingListTests.java4
-rw-r--r--spring-core/src/test/java/org/springframework/util/DigestUtilsTests.java32
-rw-r--r--spring-core/src/test/java/org/springframework/util/LinkedCaseInsensitiveMapTests.java22
-rw-r--r--spring-core/src/test/java/org/springframework/util/MimeTypeTests.java15
-rw-r--r--spring-core/src/test/java/org/springframework/util/NumberUtilsTests.java19
-rw-r--r--spring-core/src/test/java/org/springframework/util/ResizableByteArrayOutputStreamTests.java2
-rw-r--r--spring-core/src/test/java/org/springframework/util/StreamUtilsTests.java10
-rw-r--r--spring-core/src/test/java/org/springframework/util/xml/AbstractStaxHandlerTestCase.java2
-rw-r--r--spring-core/src/test/java/org/springframework/util/xml/AbstractStaxXMLReaderTestCase.java8
38 files changed, 2151 insertions, 1151 deletions
diff --git a/spring-core/src/test/java/org/springframework/core/GenericTypeResolverTests.java b/spring-core/src/test/java/org/springframework/core/GenericTypeResolverTests.java
index 1fed0c5b..7e7c3d5b 100644
--- a/spring-core/src/test/java/org/springframework/core/GenericTypeResolverTests.java
+++ b/spring-core/src/test/java/org/springframework/core/GenericTypeResolverTests.java
@@ -130,7 +130,7 @@ public class GenericTypeResolverTests {
Type t = null;
Type x = null;
for (Map.Entry<TypeVariable, Type> entry : map.entrySet()) {
- if(entry.getKey().toString().equals("T")) {
+ if (entry.getKey().toString().equals("T")) {
t = entry.getValue();
}
else {
diff --git a/spring-core/src/test/java/org/springframework/core/SerializableTypeWrapperTests.java b/spring-core/src/test/java/org/springframework/core/SerializableTypeWrapperTests.java
index ac68dace..ba669e0b 100644
--- a/spring-core/src/test/java/org/springframework/core/SerializableTypeWrapperTests.java
+++ b/spring-core/src/test/java/org/springframework/core/SerializableTypeWrapperTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2013 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -46,7 +46,7 @@ public class SerializableTypeWrapperTests {
public void forField() throws Exception {
Type type = SerializableTypeWrapper.forField(Fields.class.getField("parameterizedType"));
assertThat(type.toString(), equalTo("java.util.List<java.lang.String>"));
- assertSerialzable(type);
+ assertSerializable(type);
}
@Test
@@ -54,7 +54,7 @@ public class SerializableTypeWrapperTests {
Method method = Methods.class.getDeclaredMethod("method", Class.class, Object.class);
Type type = SerializableTypeWrapper.forMethodParameter(MethodParameter.forMethodOrConstructor(method, 0));
assertThat(type.toString(), equalTo("java.lang.Class<T>"));
- assertSerialzable(type);
+ assertSerializable(type);
}
@Test
@@ -62,62 +62,62 @@ public class SerializableTypeWrapperTests {
Constructor<?> constructor = Constructors.class.getDeclaredConstructor(List.class);
Type type = SerializableTypeWrapper.forMethodParameter(MethodParameter.forMethodOrConstructor(constructor, 0));
assertThat(type.toString(), equalTo("java.util.List<java.lang.String>"));
- assertSerialzable(type);
+ assertSerializable(type);
}
@Test
public void forGenericSuperClass() throws Exception {
Type type = SerializableTypeWrapper.forGenericSuperclass(ArrayList.class);
assertThat(type.toString(), equalTo("java.util.AbstractList<E>"));
- assertSerialzable(type);
+ assertSerializable(type);
}
@Test
public void forGenericInterfaces() throws Exception {
Type type = SerializableTypeWrapper.forGenericInterfaces(List.class)[0];
assertThat(type.toString(), equalTo("java.util.Collection<E>"));
- assertSerialzable(type);
+ assertSerializable(type);
}
@Test
- public void forTypeParamters() throws Exception {
+ public void forTypeParameters() throws Exception {
Type type = SerializableTypeWrapper.forTypeParameters(List.class)[0];
assertThat(type.toString(), equalTo("E"));
- assertSerialzable(type);
+ assertSerializable(type);
}
@Test
public void classType() throws Exception {
Type type = SerializableTypeWrapper.forField(Fields.class.getField("classType"));
assertThat(type.toString(), equalTo("class java.lang.String"));
- assertSerialzable(type);
+ assertSerializable(type);
}
@Test
public void genericArrayType() throws Exception {
GenericArrayType type = (GenericArrayType) SerializableTypeWrapper.forField(Fields.class.getField("genericArrayType"));
assertThat(type.toString(), equalTo("java.util.List<java.lang.String>[]"));
- assertSerialzable(type);
- assertSerialzable(type.getGenericComponentType());
+ assertSerializable(type);
+ assertSerializable(type.getGenericComponentType());
}
@Test
public void parameterizedType() throws Exception {
ParameterizedType type = (ParameterizedType) SerializableTypeWrapper.forField(Fields.class.getField("parameterizedType"));
assertThat(type.toString(), equalTo("java.util.List<java.lang.String>"));
- assertSerialzable(type);
- assertSerialzable(type.getOwnerType());
- assertSerialzable(type.getRawType());
- assertSerialzable(type.getActualTypeArguments());
- assertSerialzable(type.getActualTypeArguments()[0]);
+ assertSerializable(type);
+ assertSerializable(type.getOwnerType());
+ assertSerializable(type.getRawType());
+ assertSerializable(type.getActualTypeArguments());
+ assertSerializable(type.getActualTypeArguments()[0]);
}
@Test
public void typeVariableType() throws Exception {
TypeVariable<?> type = (TypeVariable<?>) SerializableTypeWrapper.forField(Fields.class.getField("typeVariableType"));
assertThat(type.toString(), equalTo("T"));
- assertSerialzable(type);
- assertSerialzable(type.getBounds());
+ assertSerializable(type);
+ assertSerializable(type.getBounds());
}
@Test
@@ -125,13 +125,13 @@ public class SerializableTypeWrapperTests {
ParameterizedType typeSource = (ParameterizedType) SerializableTypeWrapper.forField(Fields.class.getField("wildcardType"));
WildcardType type = (WildcardType) typeSource.getActualTypeArguments()[0];
assertThat(type.toString(), equalTo("? extends java.lang.CharSequence"));
- assertSerialzable(type);
- assertSerialzable(type.getLowerBounds());
- assertSerialzable(type.getUpperBounds());
+ assertSerializable(type);
+ assertSerializable(type.getLowerBounds());
+ assertSerializable(type.getUpperBounds());
}
- private void assertSerialzable(Object source) throws Exception {
+ private void assertSerializable(Object source) throws Exception {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(source);
@@ -152,19 +152,19 @@ public class SerializableTypeWrapperTests {
public T typeVariableType;
public List<? extends CharSequence> wildcardType;
-
}
- static interface Methods {
- <T> List<T> method(Class<T> p1, T p2);
+ interface Methods {
+ <T> List<T> method(Class<T> p1, T p2);
}
+
static class Constructors {
public Constructors(List<String> p) {
}
-
}
+
}
diff --git a/spring-core/src/test/java/org/springframework/core/annotation/AnnotatedElementUtilsTests.java b/spring-core/src/test/java/org/springframework/core/annotation/AnnotatedElementUtilsTests.java
index 57dd9847..8230dd59 100644
--- a/spring-core/src/test/java/org/springframework/core/annotation/AnnotatedElementUtilsTests.java
+++ b/spring-core/src/test/java/org/springframework/core/annotation/AnnotatedElementUtilsTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2015 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -33,8 +33,11 @@ import javax.annotation.Resource;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.internal.ArrayComparisonFailure;
import org.junit.rules.ExpectedException;
+import org.springframework.core.annotation.AnnotationUtilsTests.WebController;
+import org.springframework.core.annotation.AnnotationUtilsTests.WebMapping;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.MultiValueMap;
@@ -44,6 +47,7 @@ import static java.util.stream.Collectors.*;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.springframework.core.annotation.AnnotatedElementUtils.*;
+import static org.springframework.core.annotation.AnnotationUtilsTests.*;
/**
* Unit tests for {@link AnnotatedElementUtils}.
@@ -51,6 +55,9 @@ import static org.springframework.core.annotation.AnnotatedElementUtils.*;
* @author Sam Brannen
* @author Rossen Stoyanchev
* @since 4.0.3
+ * @see AnnotationUtilsTests
+ * @see MultipleComposedAnnotationsOnSingleAnnotatedElementTests
+ * @see ComposedRepeatableAnnotationsTests
*/
public class AnnotatedElementUtilsTests {
@@ -63,18 +70,25 @@ public class AnnotatedElementUtilsTests {
@Test
public void getMetaAnnotationTypesOnNonAnnotatedClass() {
assertNull(getMetaAnnotationTypes(NonAnnotatedClass.class, TransactionalComponent.class));
+ assertNull(getMetaAnnotationTypes(NonAnnotatedClass.class, TransactionalComponent.class.getName()));
}
@Test
public void getMetaAnnotationTypesOnClassWithMetaDepth1() {
Set<String> names = getMetaAnnotationTypes(TransactionalComponentClass.class, TransactionalComponent.class);
assertEquals(names(Transactional.class, Component.class), names);
+
+ names = getMetaAnnotationTypes(TransactionalComponentClass.class, TransactionalComponent.class.getName());
+ assertEquals(names(Transactional.class, Component.class), names);
}
@Test
public void getMetaAnnotationTypesOnClassWithMetaDepth2() {
Set<String> names = getMetaAnnotationTypes(ComposedTransactionalComponentClass.class, ComposedTransactionalComponent.class);
assertEquals(names(TransactionalComponent.class, Transactional.class, Component.class), names);
+
+ names = getMetaAnnotationTypes(ComposedTransactionalComponentClass.class, ComposedTransactionalComponent.class.getName());
+ assertEquals(names(TransactionalComponent.class, Transactional.class, Component.class), names);
}
@Test
@@ -294,7 +308,15 @@ public class AnnotatedElementUtilsTests {
assertTrue(isAnnotated(element, name));
}
- @Ignore("Disabled until SPR-13554 is addressed")
+ /**
+ * This test should never pass, simply because Spring does not support a hybrid
+ * approach for annotation attribute overrides with transitive implicit aliases.
+ * See SPR-13554 for details.
+ * <p>Furthermore, if you choose to execute this test, it can fail for either
+ * the first test class or the second one (with different exceptions), depending
+ * on the order in which the JVM returns the attribute methods via reflection.
+ */
+ @Ignore("Permanently disabled but left in place for illustrative purposes")
@Test
public void getMergedAnnotationAttributesWithHalfConventionBasedAndHalfAliasedComposedAnnotation() {
for (Class<?> clazz : asList(HalfConventionBasedAndHalfAliasedComposedContextConfigClassV1.class,
@@ -380,10 +402,20 @@ public class AnnotatedElementUtilsTests {
}
@Test
+ public void getMergedAnnotationWithTransitiveImplicitAliasesWithSingleElementOverridingAnArrayViaAliasFor() {
+ assertGetMergedAnnotation(SingleLocationTransitiveImplicitAliasesContextConfigClass.class, "test.groovy");
+ }
+
+ @Test
public void getMergedAnnotationWithTransitiveImplicitAliasesWithSkippedLevel() {
assertGetMergedAnnotation(TransitiveImplicitAliasesWithSkippedLevelContextConfigClass.class, "test.xml");
}
+ @Test
+ public void getMergedAnnotationWithTransitiveImplicitAliasesWithSkippedLevelWithSingleElementOverridingAnArrayViaAliasFor() {
+ assertGetMergedAnnotation(SingleLocationTransitiveImplicitAliasesWithSkippedLevelContextConfigClass.class, "test.xml");
+ }
+
private void assertGetMergedAnnotation(Class<?> element, String... expected) {
String name = ContextConfig.class.getName();
ContextConfig contextConfig = getMergedAnnotation(element, ContextConfig.class);
@@ -428,15 +460,15 @@ public class AnnotatedElementUtilsTests {
}
@Test
- public void getMergedAnnotationAttributesWithInvalidAliasedComposedAnnotation() {
- Class<?> element = InvalidAliasedComposedContextConfigClass.class;
- exception.expect(AnnotationConfigurationException.class);
- exception.expectMessage(either(containsString("attribute 'value' and its alias 'locations'")).or(
- containsString("attribute 'locations' and its alias 'value'")));
- exception.expectMessage(either(containsString("values of [{duplicateDeclaration}] and [{test.xml}]")).or(
- containsString("values of [{test.xml}] and [{duplicateDeclaration}]")));
- exception.expectMessage(containsString("but only one is permitted"));
- getMergedAnnotationAttributes(element, ContextConfig.class);
+ public void getMergedAnnotationAttributesWithShadowedAliasComposedAnnotation() {
+ Class<?> element = ShadowedAliasComposedContextConfigClass.class;
+ AnnotationAttributes attributes = getMergedAnnotationAttributes(element, ContextConfig.class);
+
+ String[] expected = asArray("test.xml");
+
+ assertNotNull("Should find @ContextConfig on " + element.getSimpleName(), attributes);
+ assertArrayEquals("locations", expected, attributes.getStringArray("locations"));
+ assertArrayEquals("value", expected, attributes.getStringArray("value"));
}
@Test
@@ -561,6 +593,52 @@ public class AnnotatedElementUtilsTests {
}
@Test
+ public void findMergedAnnotationAttributesOnClassWithAttributeAliasInComposedAnnotationAndNestedAnnotationsInTargetAnnotation() {
+ AnnotationAttributes attributes = assertComponentScanAttributes(TestComponentScanClass.class, "com.example.app.test");
+
+ Filter[] excludeFilters = attributes.getAnnotationArray("excludeFilters", Filter.class);
+ assertNotNull(excludeFilters);
+
+ List<String> patterns = stream(excludeFilters).map(Filter::pattern).collect(toList());
+ assertEquals(asList("*Test", "*Tests"), patterns);
+ }
+
+ /**
+ * This test ensures that {@link AnnotationUtils#postProcessAnnotationAttributes}
+ * uses {@code ObjectUtils.nullSafeEquals()} to check for equality between annotation
+ * attributes since attributes may be arrays.
+ */
+ @Test
+ public void findMergedAnnotationAttributesOnClassWithBothAttributesOfAnAliasPairDeclared() {
+ assertComponentScanAttributes(ComponentScanWithBasePackagesAndValueAliasClass.class, "com.example.app.test");
+ }
+
+ @Test
+ public void findMergedAnnotationAttributesWithSingleElementOverridingAnArrayViaConvention() {
+ assertComponentScanAttributes(ConventionBasedSinglePackageComponentScanClass.class, "com.example.app.test");
+ }
+
+ @Test
+ public void findMergedAnnotationAttributesWithSingleElementOverridingAnArrayViaAliasFor() {
+ assertComponentScanAttributes(AliasForBasedSinglePackageComponentScanClass.class, "com.example.app.test");
+ }
+
+ private AnnotationAttributes assertComponentScanAttributes(Class<?> element, String... expected) {
+ AnnotationAttributes attributes = findMergedAnnotationAttributes(element, ComponentScan.class);
+
+ assertNotNull("Should find @ComponentScan on " + element, attributes);
+ assertArrayEquals("value: ", expected, attributes.getStringArray("value"));
+ assertArrayEquals("basePackages: ", expected, attributes.getStringArray("basePackages"));
+
+ return attributes;
+ }
+
+ private AnnotationAttributes findMergedAnnotationAttributes(AnnotatedElement element, Class<? extends Annotation> annotationType) {
+ Assert.notNull(annotationType, "annotationType must not be null");
+ return AnnotatedElementUtils.findMergedAnnotationAttributes(element, annotationType.getName(), false, false);
+ }
+
+ @Test
public void findMergedAnnotationWithAttributeAliasesInTargetAnnotation() {
Class<?> element = AliasedTransactionalComponentClass.class;
AliasedTransactional annotation = findMergedAnnotation(element, AliasedTransactional.class);
@@ -594,38 +672,6 @@ public class AnnotatedElementUtilsTests {
}
@Test
- public void findMergedAnnotationAttributesOnClassWithAttributeAliasInComposedAnnotationAndNestedAnnotationsInTargetAnnotation() {
- String[] expected = asArray("com.example.app.test");
- Class<?> element = TestComponentScanClass.class;
- AnnotationAttributes attributes = findMergedAnnotationAttributes(element, ComponentScan.class);
-
- assertNotNull("Should find @ComponentScan on " + element, attributes);
- assertArrayEquals("basePackages for " + element, expected, attributes.getStringArray("basePackages"));
-
- Filter[] excludeFilters = attributes.getAnnotationArray("excludeFilters", Filter.class);
- assertNotNull(excludeFilters);
-
- List<String> patterns = stream(excludeFilters).map(Filter::pattern).collect(toList());
- assertEquals(asList("*Test", "*Tests"), patterns);
- }
-
- /**
- * This test ensures that {@link AnnotationUtils#postProcessAnnotationAttributes}
- * uses {@code ObjectUtils.nullSafeEquals()} to check for equality between annotation
- * attributes since attributes may be arrays.
- */
- @Test
- public void findMergedAnnotationAttributesOnClassWithBothAttributesOfAnAliasPairDeclared() {
- String[] expected = asArray("com.example.app.test");
- Class<?> element = ComponentScanWithBasePackagesAndValueAliasClass.class;
- AnnotationAttributes attributes = findMergedAnnotationAttributes(element, ComponentScan.class);
-
- assertNotNull("Should find @ComponentScan on " + element, attributes);
- assertArrayEquals("value: ", expected, attributes.getStringArray("value"));
- assertArrayEquals("basePackages: ", expected, attributes.getStringArray("basePackages"));
- }
-
- @Test
public void findMergedAnnotationWithLocalAliasesThatConflictWithAttributesInMetaAnnotationByConvention() {
final String[] EMPTY = new String[0];
Class<?> element = SpringAppConfigClass.class;
@@ -639,6 +685,24 @@ public class AnnotatedElementUtilsTests {
}
@Test
+ public void findMergedAnnotationWithSingleElementOverridingAnArrayViaConvention() throws Exception {
+ assertWebMapping(WebController.class.getMethod("postMappedWithPathAttribute"));
+ }
+
+ @Test
+ public void findMergedAnnotationWithSingleElementOverridingAnArrayViaAliasFor() throws Exception {
+ assertWebMapping(WebController.class.getMethod("getMappedWithValueAttribute"));
+ assertWebMapping(WebController.class.getMethod("getMappedWithPathAttribute"));
+ }
+
+ private void assertWebMapping(AnnotatedElement element) throws ArrayComparisonFailure {
+ WebMapping webMapping = findMergedAnnotation(element, WebMapping.class);
+ assertNotNull(webMapping);
+ assertArrayEquals("value attribute: ", asArray("/test"), webMapping.value());
+ assertArrayEquals("path attribute: ", asArray("/test"), webMapping.path());
+ }
+
+ @Test
public void javaLangAnnotationTypeViaFindMergedAnnotation() throws Exception {
Constructor<?> deprecatedCtor = Date.class.getConstructor(String.class);
assertEquals(deprecatedCtor.getAnnotation(Deprecated.class), findMergedAnnotation(deprecatedCtor, Deprecated.class));
@@ -651,28 +715,10 @@ public class AnnotatedElementUtilsTests {
assertEquals(SpringAppConfigClass.class.getAnnotation(Resource.class), findMergedAnnotation(SpringAppConfigClass.class, Resource.class));
}
-
private Set<String> names(Class<?>... classes) {
return stream(classes).map(Class::getName).collect(toSet());
}
- @SafeVarargs
- // The following "varargs" suppression is necessary for javac from OpenJDK
- // (1.8.0_60-b27); however, Eclipse warns that it's unnecessary. See the following
- // Eclipse issues for details.
- //
- // https://bugs.eclipse.org/bugs/show_bug.cgi?id=344783
- // https://bugs.eclipse.org/bugs/show_bug.cgi?id=349669#c10
- // @SuppressWarnings("varargs")
- private static <T> T[] asArray(T... arr) {
- return arr;
- }
-
- private static AnnotationAttributes findMergedAnnotationAttributes(AnnotatedElement element, Class<? extends Annotation> annotationType) {
- Assert.notNull(annotationType, "annotationType must not be null");
- return AnnotatedElementUtils.findMergedAnnotationAttributes(element, annotationType.getName(), false, false);
- }
-
// -------------------------------------------------------------------------
@@ -821,6 +867,10 @@ public class AnnotatedElementUtilsTests {
String[] locations();
}
+ /**
+ * This hybrid approach for annotation attribute overrides with transitive implicit
+ * aliases is unsupported. See SPR-13554 for details.
+ */
@ContextConfig
@Retention(RetentionPolicy.RUNTIME)
@interface HalfConventionBasedAndHalfAliasedComposedContextConfig {
@@ -858,10 +908,12 @@ public class AnnotatedElementUtilsTests {
@AliasFor(annotation = ContextConfig.class, attribute = "locations")
String[] xmlFiles() default {};
- @AliasFor(annotation = ContextConfig.class, attribute = "locations")
+ // intentionally omitted: attribute = "locations"
+ @AliasFor(annotation = ContextConfig.class)
String[] locations() default {};
- @AliasFor(annotation = ContextConfig.class, attribute = "locations")
+ // intentionally omitted: attribute = "locations" (SPR-14069)
+ @AliasFor(annotation = ContextConfig.class)
String[] value() default {};
}
@@ -883,6 +935,17 @@ public class AnnotatedElementUtilsTests {
@ImplicitAliasesContextConfig
@Retention(RetentionPolicy.RUNTIME)
+ @interface SingleLocationTransitiveImplicitAliasesContextConfig {
+
+ @AliasFor(annotation = ImplicitAliasesContextConfig.class, attribute = "xmlFiles")
+ String xml() default "";
+
+ @AliasFor(annotation = ImplicitAliasesContextConfig.class, attribute = "groovyScripts")
+ String groovy() default "";
+ }
+
+ @ImplicitAliasesContextConfig
+ @Retention(RetentionPolicy.RUNTIME)
@interface TransitiveImplicitAliasesWithSkippedLevelContextConfig {
@AliasFor(annotation = ContextConfig.class, attribute = "locations")
@@ -892,15 +955,28 @@ public class AnnotatedElementUtilsTests {
String[] groovy() default {};
}
+ @ImplicitAliasesContextConfig
+ @Retention(RetentionPolicy.RUNTIME)
+ @interface SingleLocationTransitiveImplicitAliasesWithSkippedLevelContextConfig {
+
+ @AliasFor(annotation = ContextConfig.class, attribute = "locations")
+ String xml() default "";
+
+ @AliasFor(annotation = ImplicitAliasesContextConfig.class, attribute = "groovyScripts")
+ String groovy() default "";
+ }
+
/**
- * Invalid because the configuration declares a value for 'value' and
- * requires a value for the aliased 'locations'. So we likely end up with
- * both 'value' and 'locations' being present in {@link AnnotationAttributes}
- * but with different values, which violates the contract of {@code @AliasFor}.
+ * Although the configuration declares an explicit value for 'value' and
+ * requires a value for the aliased 'locations', this does not result in
+ * an error since 'locations' effectively <em>shadows</em> the 'value'
+ * attribute (which cannot be set via the composed annotation anyway).
+ *
+ * If 'value' were not shadowed, such a declaration would not make sense.
*/
@ContextConfig(value = "duplicateDeclaration")
@Retention(RetentionPolicy.RUNTIME)
- @interface InvalidAliasedComposedContextConfig {
+ @interface ShadowedAliasComposedContextConfig {
@AliasFor(annotation = ContextConfig.class, attribute = "locations")
String[] xmlConfigFiles();
@@ -962,6 +1038,21 @@ public class AnnotatedElementUtilsTests {
String[] packages();
}
+ @ComponentScan
+ @Retention(RetentionPolicy.RUNTIME)
+ @interface ConventionBasedSinglePackageComponentScan {
+
+ String basePackages();
+ }
+
+ @ComponentScan
+ @Retention(RetentionPolicy.RUNTIME)
+ @interface AliasForBasedSinglePackageComponentScan {
+
+ @AliasFor(attribute = "basePackages", annotation = ComponentScan.class)
+ String pkg();
+ }
+
// -------------------------------------------------------------------------
static class NonAnnotatedClass {
@@ -1132,16 +1223,24 @@ public class AnnotatedElementUtilsTests {
static class TransitiveImplicitAliasesContextConfigClass {
}
+ @SingleLocationTransitiveImplicitAliasesContextConfig(groovy = "test.groovy")
+ static class SingleLocationTransitiveImplicitAliasesContextConfigClass {
+ }
+
@TransitiveImplicitAliasesWithSkippedLevelContextConfig(xml = "test.xml")
static class TransitiveImplicitAliasesWithSkippedLevelContextConfigClass {
}
+ @SingleLocationTransitiveImplicitAliasesWithSkippedLevelContextConfig(xml = "test.xml")
+ static class SingleLocationTransitiveImplicitAliasesWithSkippedLevelContextConfigClass {
+ }
+
@ComposedImplicitAliasesContextConfig
static class ComposedImplicitAliasesContextConfigClass {
}
- @InvalidAliasedComposedContextConfig(xmlConfigFiles = "test.xml")
- static class InvalidAliasedComposedContextConfigClass {
+ @ShadowedAliasComposedContextConfig(xmlConfigFiles = "test.xml")
+ static class ShadowedAliasComposedContextConfigClass {
}
@AliasedComposedContextConfigAndTestPropSource(xmlConfigFiles = "test.xml")
@@ -1156,6 +1255,14 @@ public class AnnotatedElementUtilsTests {
static class TestComponentScanClass {
}
+ @ConventionBasedSinglePackageComponentScan(basePackages = "com.example.app.test")
+ static class ConventionBasedSinglePackageComponentScanClass {
+ }
+
+ @AliasForBasedSinglePackageComponentScan(pkg = "com.example.app.test")
+ static class AliasForBasedSinglePackageComponentScanClass {
+ }
+
@SpringAppConfig(Number.class)
static class SpringAppConfigClass {
}
diff --git a/spring-core/src/test/java/org/springframework/core/annotation/AnnotationAttributesTests.java b/spring-core/src/test/java/org/springframework/core/annotation/AnnotationAttributesTests.java
index 57cdd7ab..5908bf36 100644
--- a/spring-core/src/test/java/org/springframework/core/annotation/AnnotationAttributesTests.java
+++ b/spring-core/src/test/java/org/springframework/core/annotation/AnnotationAttributesTests.java
@@ -25,7 +25,6 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.springframework.core.annotation.AnnotationUtilsTests.ContextConfig;
import org.springframework.core.annotation.AnnotationUtilsTests.ImplicitAliasesContextConfig;
import static org.hamcrest.CoreMatchers.*;
@@ -133,21 +132,21 @@ public class AnnotationAttributesTests {
@Test
public void getEnumWithNullAttributeName() {
exception.expect(IllegalArgumentException.class);
- exception.expectMessage(containsString("attributeName must not be null or empty"));
+ exception.expectMessage("must not be null or empty");
attributes.getEnum(null);
}
@Test
public void getEnumWithEmptyAttributeName() {
exception.expect(IllegalArgumentException.class);
- exception.expectMessage(containsString("attributeName must not be null or empty"));
+ exception.expectMessage("must not be null or empty");
attributes.getEnum("");
}
@Test
public void getEnumWithUnknownAttributeName() {
exception.expect(IllegalArgumentException.class);
- exception.expectMessage(containsString("Attribute 'bogus' not found"));
+ exception.expectMessage("Attribute 'bogus' not found");
attributes.getEnum("bogus");
}
@@ -160,334 +159,66 @@ public class AnnotationAttributesTests {
}
@Test
- public void getAliasedString() {
- final String value = "metaverse";
-
- attributes.clear();
- attributes.put("name", value);
- assertEquals(value, getAliasedString("name"));
- assertEquals(value, getAliasedString("value"));
-
- attributes.clear();
- attributes.put("value", value);
- assertEquals(value, getAliasedString("name"));
- assertEquals(value, getAliasedString("value"));
-
- attributes.clear();
- attributes.put("name", value);
- attributes.put("value", value);
- assertEquals(value, getAliasedString("name"));
- assertEquals(value, getAliasedString("value"));
- }
-
- @Test
public void getAliasedStringWithImplicitAliases() {
- final String value = "metaverse";
- final List<String> aliases = Arrays.asList("value", "location1", "location2", "location3", "xmlFile", "groovyScript");
+ String value = "metaverse";
+ List<String> aliases = Arrays.asList("value", "location1", "location2", "location3", "xmlFile", "groovyScript");
attributes = new AnnotationAttributes(ImplicitAliasesContextConfig.class);
attributes.put("value", value);
- aliases.stream().forEach(alias -> assertEquals(value, getAliasedStringWithImplicitAliases(alias)));
+ AnnotationUtils.postProcessAnnotationAttributes(null, attributes, false);
+ aliases.stream().forEach(alias -> assertEquals(value, attributes.getString(alias)));
- attributes.clear();
+ attributes = new AnnotationAttributes(ImplicitAliasesContextConfig.class);
attributes.put("location1", value);
- aliases.stream().forEach(alias -> assertEquals(value, getAliasedStringWithImplicitAliases(alias)));
+ AnnotationUtils.postProcessAnnotationAttributes(null, attributes, false);
+ aliases.stream().forEach(alias -> assertEquals(value, attributes.getString(alias)));
- attributes.clear();
+ attributes = new AnnotationAttributes(ImplicitAliasesContextConfig.class);
attributes.put("value", value);
attributes.put("location1", value);
attributes.put("xmlFile", value);
attributes.put("groovyScript", value);
- aliases.stream().forEach(alias -> assertEquals(value, getAliasedStringWithImplicitAliases(alias)));
- }
-
- @Test
- public void getAliasedStringWithImplicitAliasesWithMissingAliasedAttributes() {
- final List<String> aliases = Arrays.asList("value", "location1", "location2", "location3", "xmlFile", "groovyScript");
- attributes = new AnnotationAttributes(ImplicitAliasesContextConfig.class);
-
- exception.expect(IllegalArgumentException.class);
- exception.expectMessage(startsWith("Neither attribute 'value' nor one of its aliases ["));
- aliases.stream().forEach(alias -> exception.expectMessage(containsString(alias)));
- exception.expectMessage(endsWith("] was found in attributes for annotation [" + ImplicitAliasesContextConfig.class.getName() + "]"));
- getAliasedStringWithImplicitAliases("value");
- }
-
- @Test
- public void getAliasedStringFromSynthesizedAnnotationAttributes() {
- Scope scope = ScopedComponent.class.getAnnotation(Scope.class);
- AnnotationAttributes scopeAttributes = AnnotationUtils.getAnnotationAttributes(ScopedComponent.class, scope);
-
- assertEquals("custom", getAliasedString(scopeAttributes, "name"));
- assertEquals("custom", getAliasedString(scopeAttributes, "value"));
- }
-
- @Test
- public void getAliasedStringWithMissingAliasedAttributes() {
- exception.expect(IllegalArgumentException.class);
- exception.expectMessage(equalTo("Neither attribute 'name' nor one of its aliases [value] was found in attributes for annotation [unknown]"));
- getAliasedString("name");
- }
-
- @Test
- public void getAliasedStringWithDifferentAliasedValues() {
- attributes.put("name", "request");
- attributes.put("value", "session");
-
- exception.expect(AnnotationConfigurationException.class);
- exception.expectMessage(containsString("In annotation [" + Scope.class.getName() + "]"));
- exception.expectMessage(containsString("attribute [name] and its alias [value]"));
- exception.expectMessage(containsString("[request] and [session]"));
- exception.expectMessage(containsString("but only one is permitted"));
-
- getAliasedString("name");
- }
-
- private String getAliasedString(String attributeName) {
- return getAliasedString(this.attributes, attributeName);
- }
-
- private String getAliasedString(AnnotationAttributes attrs, String attributeName) {
- return attrs.getAliasedString(attributeName, Scope.class, null);
- }
-
- private String getAliasedStringWithImplicitAliases(String attributeName) {
- return this.attributes.getAliasedString(attributeName, ImplicitAliasesContextConfig.class, null);
- }
-
- @Test
- public void getAliasedStringArray() {
- final String[] INPUT = new String[] {"test.xml"};
- final String[] EMPTY = new String[0];
-
- attributes.clear();
- attributes.put("location", INPUT);
- assertArrayEquals(INPUT, getAliasedStringArray("location"));
- assertArrayEquals(INPUT, getAliasedStringArray("value"));
-
- attributes.clear();
- attributes.put("value", INPUT);
- assertArrayEquals(INPUT, getAliasedStringArray("location"));
- assertArrayEquals(INPUT, getAliasedStringArray("value"));
-
- attributes.clear();
- attributes.put("location", INPUT);
- attributes.put("value", INPUT);
- assertArrayEquals(INPUT, getAliasedStringArray("location"));
- assertArrayEquals(INPUT, getAliasedStringArray("value"));
-
- attributes.clear();
- attributes.put("location", INPUT);
- attributes.put("value", EMPTY);
- assertArrayEquals(INPUT, getAliasedStringArray("location"));
- assertArrayEquals(INPUT, getAliasedStringArray("value"));
-
- attributes.clear();
- attributes.put("location", EMPTY);
- attributes.put("value", INPUT);
- assertArrayEquals(INPUT, getAliasedStringArray("location"));
- assertArrayEquals(INPUT, getAliasedStringArray("value"));
-
- attributes.clear();
- attributes.put("location", EMPTY);
- attributes.put("value", EMPTY);
- assertArrayEquals(EMPTY, getAliasedStringArray("location"));
- assertArrayEquals(EMPTY, getAliasedStringArray("value"));
+ AnnotationUtils.postProcessAnnotationAttributes(null, attributes, false);
+ aliases.stream().forEach(alias -> assertEquals(value, attributes.getString(alias)));
}
@Test
public void getAliasedStringArrayWithImplicitAliases() {
- final String[] INPUT = new String[] {"test.xml"};
- final String[] EMPTY = new String[0];
- final List<String> aliases = Arrays.asList("value", "location1", "location2", "location3", "xmlFile", "groovyScript");
+ String[] value = new String[] {"test.xml"};
+ List<String> aliases = Arrays.asList("value", "location1", "location2", "location3", "xmlFile", "groovyScript");
attributes = new AnnotationAttributes(ImplicitAliasesContextConfig.class);
+ attributes.put("location1", value);
+ AnnotationUtils.postProcessAnnotationAttributes(null, attributes, false);
+ aliases.stream().forEach(alias -> assertArrayEquals(value, attributes.getStringArray(alias)));
- attributes.put("location1", INPUT);
- aliases.stream().forEach(alias -> assertArrayEquals(INPUT, getAliasedStringArrayWithImplicitAliases(alias)));
-
- attributes.clear();
- attributes.put("value", INPUT);
- aliases.stream().forEach(alias -> assertArrayEquals(INPUT, getAliasedStringArrayWithImplicitAliases(alias)));
-
- attributes.clear();
- attributes.put("location1", INPUT);
- attributes.put("value", INPUT);
- aliases.stream().forEach(alias -> assertArrayEquals(INPUT, getAliasedStringArrayWithImplicitAliases(alias)));
-
- attributes.clear();
- attributes.put("location1", INPUT);
- attributes.put("value", EMPTY);
- aliases.stream().forEach(alias -> assertArrayEquals(INPUT, getAliasedStringArrayWithImplicitAliases(alias)));
-
- attributes.clear();
- attributes.put("location1", EMPTY);
- attributes.put("value", INPUT);
- aliases.stream().forEach(alias -> assertArrayEquals(INPUT, getAliasedStringArrayWithImplicitAliases(alias)));
-
- attributes.clear();
- attributes.put("location1", EMPTY);
- attributes.put("value", EMPTY);
- aliases.stream().forEach(alias -> assertArrayEquals(EMPTY, getAliasedStringArrayWithImplicitAliases(alias)));
- }
-
- @Test
- public void getAliasedStringArrayWithImplicitAliasesWithMissingAliasedAttributes() {
- final List<String> aliases = Arrays.asList("value", "location1", "location2", "location3", "xmlFile", "groovyScript");
attributes = new AnnotationAttributes(ImplicitAliasesContextConfig.class);
-
- exception.expect(IllegalArgumentException.class);
- exception.expectMessage(startsWith("Neither attribute 'value' nor one of its aliases ["));
- aliases.stream().forEach(alias -> exception.expectMessage(containsString(alias)));
- exception.expectMessage(endsWith("] was found in attributes for annotation [" + ImplicitAliasesContextConfig.class.getName() + "]"));
- getAliasedStringArrayWithImplicitAliases("value");
- }
-
- @Test
- public void getAliasedStringArrayWithMissingAliasedAttributes() {
- exception.expect(IllegalArgumentException.class);
- exception.expectMessage(equalTo("Neither attribute 'location' nor one of its aliases [value] was found in attributes for annotation [unknown]"));
- getAliasedStringArray("location");
- }
-
- @Test
- public void getAliasedStringArrayWithDifferentAliasedValues() {
- attributes.put("location", new String[] {"1.xml"});
- attributes.put("value", new String[] {"2.xml"});
-
- exception.expect(AnnotationConfigurationException.class);
- exception.expectMessage(containsString("In annotation [" + ContextConfig.class.getName() + "]"));
- exception.expectMessage(containsString("attribute [location] and its alias [value]"));
- exception.expectMessage(containsString("[{1.xml}] and [{2.xml}]"));
- exception.expectMessage(containsString("but only one is permitted"));
-
- getAliasedStringArray("location");
- }
-
- private String[] getAliasedStringArray(String attributeName) {
- // Note: even though the attributes we test against here are of type
- // String instead of String[], it doesn't matter... since
- // AnnotationAttributes does not validate the actual return type of
- // attributes in the annotation.
- return attributes.getAliasedStringArray(attributeName, ContextConfig.class, null);
- }
-
- private String[] getAliasedStringArrayWithImplicitAliases(String attributeName) {
- // Note: even though the attributes we test against here are of type
- // String instead of String[], it doesn't matter... since
- // AnnotationAttributes does not validate the actual return type of
- // attributes in the annotation.
- return this.attributes.getAliasedStringArray(attributeName, ImplicitAliasesContextConfig.class, null);
- }
-
- @Test
- public void getAliasedClassArray() {
- final Class<?>[] INPUT = new Class<?>[] {String.class};
- final Class<?>[] EMPTY = new Class<?>[0];
-
- attributes.clear();
- attributes.put("classes", INPUT);
- assertArrayEquals(INPUT, getAliasedClassArray("classes"));
- assertArrayEquals(INPUT, getAliasedClassArray("value"));
-
- attributes.clear();
- attributes.put("value", INPUT);
- assertArrayEquals(INPUT, getAliasedClassArray("classes"));
- assertArrayEquals(INPUT, getAliasedClassArray("value"));
-
- attributes.clear();
- attributes.put("classes", INPUT);
- attributes.put("value", INPUT);
- assertArrayEquals(INPUT, getAliasedClassArray("classes"));
- assertArrayEquals(INPUT, getAliasedClassArray("value"));
-
- attributes.clear();
- attributes.put("classes", INPUT);
- attributes.put("value", EMPTY);
- assertArrayEquals(INPUT, getAliasedClassArray("classes"));
- assertArrayEquals(INPUT, getAliasedClassArray("value"));
-
- attributes.clear();
- attributes.put("classes", EMPTY);
- attributes.put("value", INPUT);
- assertArrayEquals(INPUT, getAliasedClassArray("classes"));
- assertArrayEquals(INPUT, getAliasedClassArray("value"));
-
- attributes.clear();
- attributes.put("classes", EMPTY);
- attributes.put("value", EMPTY);
- assertArrayEquals(EMPTY, getAliasedClassArray("classes"));
- assertArrayEquals(EMPTY, getAliasedClassArray("value"));
- }
-
- @Test
- public void getAliasedClassArrayWithImplicitAliases() {
- final Class<?>[] INPUT = new Class<?>[] {String.class};
- final Class<?>[] EMPTY = new Class<?>[0];
- final List<String> aliases = Arrays.asList("value", "location1", "location2", "location3", "xmlFile", "groovyScript");
+ attributes.put("value", value);
+ AnnotationUtils.postProcessAnnotationAttributes(null, attributes, false);
+ aliases.stream().forEach(alias -> assertArrayEquals(value, attributes.getStringArray(alias)));
attributes = new AnnotationAttributes(ImplicitAliasesContextConfig.class);
+ attributes.put("location1", value);
+ attributes.put("value", value);
+ AnnotationUtils.postProcessAnnotationAttributes(null, attributes, false);
+ aliases.stream().forEach(alias -> assertArrayEquals(value, attributes.getStringArray(alias)));
- attributes.put("location1", INPUT);
- aliases.stream().forEach(alias -> assertArrayEquals(INPUT, getAliasedClassArrayWithImplicitAliases(alias)));
-
- attributes.clear();
- attributes.put("value", INPUT);
- aliases.stream().forEach(alias -> assertArrayEquals(INPUT, getAliasedClassArrayWithImplicitAliases(alias)));
-
- attributes.clear();
- attributes.put("location1", INPUT);
- attributes.put("value", INPUT);
- aliases.stream().forEach(alias -> assertArrayEquals(INPUT, getAliasedClassArrayWithImplicitAliases(alias)));
-
- attributes.clear();
- attributes.put("location1", INPUT);
- attributes.put("value", EMPTY);
- aliases.stream().forEach(alias -> assertArrayEquals(INPUT, getAliasedClassArrayWithImplicitAliases(alias)));
-
- attributes.clear();
- attributes.put("location1", EMPTY);
- attributes.put("value", INPUT);
- aliases.stream().forEach(alias -> assertArrayEquals(INPUT, getAliasedClassArrayWithImplicitAliases(alias)));
-
- attributes.clear();
- attributes.put("location1", EMPTY);
- attributes.put("value", EMPTY);
- aliases.stream().forEach(alias -> assertArrayEquals(EMPTY, getAliasedClassArrayWithImplicitAliases(alias)));
- }
-
- @Test
- public void getAliasedClassArrayWithMissingAliasedAttributes() {
- exception.expect(IllegalArgumentException.class);
- exception.expectMessage(equalTo("Neither attribute 'classes' nor one of its aliases [value] was found in attributes for annotation [unknown]"));
- getAliasedClassArray("classes");
- }
-
- @Test
- public void getAliasedClassArrayWithDifferentAliasedValues() {
- attributes.put("classes", new Class<?>[] {String.class});
- attributes.put("value", new Class<?>[] {Number.class});
-
- exception.expect(AnnotationConfigurationException.class);
- exception.expectMessage(containsString("In annotation [" + Filter.class.getName() + "]"));
- exception.expectMessage(containsString("attribute [classes] and its alias [value]"));
- exception.expectMessage(containsString("[{class java.lang.String}] and [{class java.lang.Number}]"));
- exception.expectMessage(containsString("but only one is permitted"));
-
- getAliasedClassArray("classes");
- }
-
+ attributes = new AnnotationAttributes(ImplicitAliasesContextConfig.class);
+ attributes.put("location1", value);
+ AnnotationUtils.registerDefaultValues(attributes);
+ AnnotationUtils.postProcessAnnotationAttributes(null, attributes, false);
+ aliases.stream().forEach(alias -> assertArrayEquals(value, attributes.getStringArray(alias)));
- private Class<?>[] getAliasedClassArray(String attributeName) {
- return attributes.getAliasedClassArray(attributeName, Filter.class, null);
- }
+ attributes = new AnnotationAttributes(ImplicitAliasesContextConfig.class);
+ attributes.put("value", value);
+ AnnotationUtils.registerDefaultValues(attributes);
+ AnnotationUtils.postProcessAnnotationAttributes(null, attributes, false);
+ aliases.stream().forEach(alias -> assertArrayEquals(value, attributes.getStringArray(alias)));
- private Class<?>[] getAliasedClassArrayWithImplicitAliases(String attributeName) {
- // Note: even though the attributes we test against here are of type
- // String instead of Class<?>[], it doesn't matter... since
- // AnnotationAttributes does not validate the actual return type of
- // attributes in the annotation.
- return this.attributes.getAliasedClassArray(attributeName, ImplicitAliasesContextConfig.class, null);
+ attributes = new AnnotationAttributes(ImplicitAliasesContextConfig.class);
+ AnnotationUtils.registerDefaultValues(attributes);
+ AnnotationUtils.postProcessAnnotationAttributes(null, attributes, false);
+ aliases.stream().forEach(alias -> assertArrayEquals(new String[] {""}, attributes.getStringArray(alias)));
}
@@ -514,23 +245,4 @@ public class AnnotationAttributesTests {
static class FilteredClass {
}
-
- /**
- * Mock of {@code org.springframework.context.annotation.Scope}.
- */
- @Retention(RetentionPolicy.RUNTIME)
- @interface Scope {
-
- @AliasFor(attribute = "name")
- String value() default "singleton";
-
- @AliasFor(attribute = "value")
- String name() default "singleton";
- }
-
-
- @Scope(name = "custom")
- static class ScopedComponent {
- }
-
}
diff --git a/spring-core/src/test/java/org/springframework/core/annotation/AnnotationUtilsTests.java b/spring-core/src/test/java/org/springframework/core/annotation/AnnotationUtilsTests.java
index cbf9e974..c8d5170c 100644
--- a/spring-core/src/test/java/org/springframework/core/annotation/AnnotationUtilsTests.java
+++ b/spring-core/src/test/java/org/springframework/core/annotation/AnnotationUtilsTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2015 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -210,8 +210,7 @@ public class AnnotationUtilsTests {
/** @since 4.1.2 */
@Test
public void findClassAnnotationFavorsMoreLocallyDeclaredComposedAnnotationsOverAnnotationsOnInterfaces() {
- Component component = findAnnotation(ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface.class,
- Component.class);
+ Component component = findAnnotation(ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface.class, Component.class);
assertNotNull(component);
assertEquals("meta2", component.value());
}
@@ -330,7 +329,7 @@ public class AnnotationUtilsTests {
@Test
public void findAnnotationDeclaringClassForTypesWithSingleCandidateType() {
// no class-level annotation
- List<Class<? extends Annotation>> transactionalCandidateList = asList(Transactional.class);
+ List<Class<? extends Annotation>> transactionalCandidateList = Collections.singletonList(Transactional.class);
assertNull(findAnnotationDeclaringClassForTypes(transactionalCandidateList, NonAnnotatedInterface.class));
assertNull(findAnnotationDeclaringClassForTypes(transactionalCandidateList, NonAnnotatedClass.class));
@@ -345,7 +344,7 @@ public class AnnotationUtilsTests {
// non-inherited class-level annotation; note: @Order is not inherited,
// but findAnnotationDeclaringClassForTypes() should still find it on classes.
- List<Class<? extends Annotation>> orderCandidateList = asList(Order.class);
+ List<Class<? extends Annotation>> orderCandidateList = Collections.singletonList(Order.class);
assertEquals(NonInheritedAnnotationInterface.class,
findAnnotationDeclaringClassForTypes(orderCandidateList, NonInheritedAnnotationInterface.class));
assertNull(findAnnotationDeclaringClassForTypes(orderCandidateList, SubNonInheritedAnnotationInterface.class));
@@ -466,8 +465,8 @@ public class AnnotationUtilsTests {
assertNotNull(attributes);
assertEquals(WebMapping.class, attributes.annotationType());
assertEquals("name attribute: ", "foo", attributes.getString("name"));
- assertEquals("value attribute: ", "/test", attributes.getString(VALUE));
- assertEquals("path attribute: ", "/test", attributes.getString("path"));
+ assertArrayEquals("value attribute: ", asArray("/test"), attributes.getStringArray(VALUE));
+ assertArrayEquals("path attribute: ", asArray("/test"), attributes.getStringArray("path"));
method = WebController.class.getMethod("handleMappedWithPathAttribute");
webMapping = method.getAnnotation(WebMapping.class);
@@ -475,15 +474,18 @@ public class AnnotationUtilsTests {
assertNotNull(attributes);
assertEquals(WebMapping.class, attributes.annotationType());
assertEquals("name attribute: ", "bar", attributes.getString("name"));
- assertEquals("value attribute: ", "/test", attributes.getString(VALUE));
- assertEquals("path attribute: ", "/test", attributes.getString("path"));
+ assertArrayEquals("value attribute: ", asArray("/test"), attributes.getStringArray(VALUE));
+ assertArrayEquals("path attribute: ", asArray("/test"), attributes.getStringArray("path"));
+ }
- method = WebController.class.getMethod("handleMappedWithDifferentPathAndValueAttributes");
- webMapping = method.getAnnotation(WebMapping.class);
+ @Test
+ public void getAnnotationAttributesWithAttributeAliasesWithDifferentValues() throws Exception {
exception.expect(AnnotationConfigurationException.class);
exception.expectMessage(containsString("attribute 'value' and its alias 'path'"));
- exception.expectMessage(containsString("values of [/enigma] and [/test]"));
- exception.expectMessage(endsWith("but only one is permitted."));
+ exception.expectMessage(containsString("values of [{/enigma}] and [{/test}]"));
+
+ Method method = WebController.class.getMethod("handleMappedWithDifferentPathAndValueAttributes");
+ WebMapping webMapping = method.getAnnotation(WebMapping.class);
getAnnotationAttributes(webMapping);
}
@@ -552,9 +554,10 @@ public class AnnotationUtilsTests {
@Test
public void getRepeatableAnnotationsDeclaredOnClassWithMissingAttributeAliasDeclaration() throws Exception {
exception.expect(AnnotationConfigurationException.class);
- exception.expectMessage(startsWith("Attribute [value] in"));
+ exception.expectMessage(startsWith("Attribute 'value' in"));
exception.expectMessage(containsString(BrokenContextConfig.class.getName()));
- exception.expectMessage(endsWith("must be declared as an @AliasFor [location]."));
+ exception.expectMessage(containsString("@AliasFor [location]"));
+
getRepeatableAnnotations(BrokenConfigHierarchyTestCase.class, BrokenContextConfig.class, BrokenHierarchy.class);
}
@@ -776,6 +779,25 @@ public class AnnotationUtilsTests {
}
@Test
+ public void getAttributeAliasNamesFromComposedAnnotationWithImplicitAliasesWithImpliedAliasNamesOmitted()
+ throws Exception {
+
+ Method value = ImplicitAliasesWithImpliedAliasNamesOmittedContextConfig.class.getDeclaredMethod("value");
+ Method location = ImplicitAliasesWithImpliedAliasNamesOmittedContextConfig.class.getDeclaredMethod("location");
+ Method xmlFile = ImplicitAliasesWithImpliedAliasNamesOmittedContextConfig.class.getDeclaredMethod("xmlFile");
+
+ // Meta-annotation attribute overrides
+ assertEquals("value", getAttributeOverrideName(value, ContextConfig.class));
+ assertEquals("location", getAttributeOverrideName(location, ContextConfig.class));
+ assertEquals("location", getAttributeOverrideName(xmlFile, ContextConfig.class));
+
+ // Implicit aliases
+ assertThat(getAttributeAliasNames(value), containsInAnyOrder("location", "xmlFile"));
+ assertThat(getAttributeAliasNames(location), containsInAnyOrder("value", "xmlFile"));
+ assertThat(getAttributeAliasNames(xmlFile), containsInAnyOrder("value", "location"));
+ }
+
+ @Test
public void getAttributeAliasNamesFromComposedAnnotationWithTransitiveImplicitAliases() throws Exception {
Method xml = TransitiveImplicitAliasesContextConfig.class.getDeclaredMethod("xml");
Method groovy = TransitiveImplicitAliasesContextConfig.class.getDeclaredMethod("groovy");
@@ -808,6 +830,26 @@ public class AnnotationUtilsTests {
}
@Test
+ public void getAttributeAliasNamesFromComposedAnnotationWithTransitiveImplicitAliasesWithImpliedAliasNamesOmitted()
+ throws Exception {
+
+ Method xml = TransitiveImplicitAliasesWithImpliedAliasNamesOmittedContextConfig.class.getDeclaredMethod("xml");
+ Method groovy = TransitiveImplicitAliasesWithImpliedAliasNamesOmittedContextConfig.class.getDeclaredMethod("groovy");
+
+ // Meta-annotation attribute overrides
+ assertEquals("location", getAttributeOverrideName(xml, ContextConfig.class));
+ assertEquals("location", getAttributeOverrideName(groovy, ContextConfig.class));
+
+ // Explicit meta-annotation attribute overrides
+ assertEquals("xmlFile", getAttributeOverrideName(xml, ImplicitAliasesWithImpliedAliasNamesOmittedContextConfig.class));
+ assertEquals("location", getAttributeOverrideName(groovy, ImplicitAliasesWithImpliedAliasNamesOmittedContextConfig.class));
+
+ // Transitive implicit aliases
+ assertThat(getAttributeAliasNames(groovy), containsInAnyOrder("xml"));
+ assertThat(getAttributeAliasNames(xml), containsInAnyOrder("groovy"));
+ }
+
+ @Test
public void synthesizeAnnotationWithoutAttributeAliases() throws Exception {
Component component = WebController.class.getAnnotation(Component.class);
assertNotNull(component);
@@ -835,17 +877,17 @@ public class AnnotationUtilsTests {
assertSame(synthesizedWebMapping, synthesizedAgainWebMapping);
assertEquals("name attribute: ", "foo", synthesizedAgainWebMapping.name());
- assertEquals("aliased path attribute: ", "/test", synthesizedAgainWebMapping.path());
- assertEquals("actual value attribute: ", "/test", synthesizedAgainWebMapping.value());
+ assertArrayEquals("aliased path attribute: ", asArray("/test"), synthesizedAgainWebMapping.path());
+ assertArrayEquals("actual value attribute: ", asArray("/test"), synthesizedAgainWebMapping.value());
}
@Test
public void synthesizeAnnotationWhereAliasForIsMissingAttributeDeclaration() throws Exception {
AliasForWithMissingAttributeDeclaration annotation = AliasForWithMissingAttributeDeclarationClass.class.getAnnotation(AliasForWithMissingAttributeDeclaration.class);
exception.expect(AnnotationConfigurationException.class);
- exception.expectMessage(startsWith("@AliasFor declaration on attribute [foo] in annotation"));
+ exception.expectMessage(startsWith("@AliasFor declaration on attribute 'foo' in annotation"));
exception.expectMessage(containsString(AliasForWithMissingAttributeDeclaration.class.getName()));
- exception.expectMessage(endsWith("is missing required 'attribute' value."));
+ exception.expectMessage(containsString("points to itself"));
synthesizeAnnotation(annotation);
}
@@ -853,10 +895,9 @@ public class AnnotationUtilsTests {
public void synthesizeAnnotationWhereAliasForHasDuplicateAttributeDeclaration() throws Exception {
AliasForWithDuplicateAttributeDeclaration annotation = AliasForWithDuplicateAttributeDeclarationClass.class.getAnnotation(AliasForWithDuplicateAttributeDeclaration.class);
exception.expect(AnnotationConfigurationException.class);
- exception.expectMessage(startsWith("In @AliasFor declared on attribute [foo] in annotation"));
+ exception.expectMessage(startsWith("In @AliasFor declared on attribute 'foo' in annotation"));
exception.expectMessage(containsString(AliasForWithDuplicateAttributeDeclaration.class.getName()));
exception.expectMessage(containsString("attribute 'attribute' and its alias 'value' are present with values of [baz] and [bar]"));
- exception.expectMessage(endsWith("but only one is permitted."));
synthesizeAnnotation(annotation);
}
@@ -864,9 +905,9 @@ public class AnnotationUtilsTests {
public void synthesizeAnnotationWithAttributeAliasForNonexistentAttribute() throws Exception {
AliasForNonexistentAttribute annotation = AliasForNonexistentAttributeClass.class.getAnnotation(AliasForNonexistentAttribute.class);
exception.expect(AnnotationConfigurationException.class);
- exception.expectMessage(startsWith("Attribute [foo] in"));
+ exception.expectMessage(startsWith("Attribute 'foo' in"));
exception.expectMessage(containsString(AliasForNonexistentAttribute.class.getName()));
- exception.expectMessage(containsString("is declared as an @AliasFor nonexistent attribute [bar]"));
+ exception.expectMessage(containsString("is declared as an @AliasFor nonexistent attribute 'bar'"));
synthesizeAnnotation(annotation);
}
@@ -875,9 +916,9 @@ public class AnnotationUtilsTests {
AliasForWithoutMirroredAliasFor annotation =
AliasForWithoutMirroredAliasForClass.class.getAnnotation(AliasForWithoutMirroredAliasFor.class);
exception.expect(AnnotationConfigurationException.class);
- exception.expectMessage(startsWith("Attribute [bar] in"));
+ exception.expectMessage(startsWith("Attribute 'bar' in"));
exception.expectMessage(containsString(AliasForWithoutMirroredAliasFor.class.getName()));
- exception.expectMessage(endsWith("must be declared as an @AliasFor [foo]."));
+ exception.expectMessage(containsString("@AliasFor [foo]"));
synthesizeAnnotation(annotation);
}
@@ -887,10 +928,10 @@ public class AnnotationUtilsTests {
AliasForWithMirroredAliasForWrongAttributeClass.class.getAnnotation(AliasForWithMirroredAliasForWrongAttribute.class);
exception.expect(AnnotationConfigurationException.class);
- exception.expectMessage(startsWith("Attribute [bar] in"));
+ exception.expectMessage(startsWith("Attribute 'bar' in"));
exception.expectMessage(containsString(AliasForWithMirroredAliasForWrongAttribute.class.getName()));
exception.expectMessage(either(containsString("must be declared as an @AliasFor [foo], not [quux]")).
- or(containsString("is declared as an @AliasFor nonexistent attribute [quux]")));
+ or(containsString("is declared as an @AliasFor nonexistent attribute 'quux'")));
synthesizeAnnotation(annotation);
}
@@ -901,9 +942,9 @@ public class AnnotationUtilsTests {
exception.expect(AnnotationConfigurationException.class);
exception.expectMessage(startsWith("Misconfigured aliases"));
exception.expectMessage(containsString(AliasForAttributeOfDifferentType.class.getName()));
- exception.expectMessage(containsString("attribute [foo]"));
- exception.expectMessage(containsString("attribute [bar]"));
- exception.expectMessage(endsWith("must declare the same return type."));
+ exception.expectMessage(containsString("attribute 'foo'"));
+ exception.expectMessage(containsString("attribute 'bar'"));
+ exception.expectMessage(containsString("same return type"));
synthesizeAnnotation(annotation);
}
@@ -914,9 +955,9 @@ public class AnnotationUtilsTests {
exception.expect(AnnotationConfigurationException.class);
exception.expectMessage(startsWith("Misconfigured aliases"));
exception.expectMessage(containsString(AliasForWithMissingDefaultValues.class.getName()));
- exception.expectMessage(containsString("attribute [foo] in annotation"));
- exception.expectMessage(containsString("attribute [bar] in annotation"));
- exception.expectMessage(endsWith("must declare default values."));
+ exception.expectMessage(containsString("attribute 'foo' in annotation"));
+ exception.expectMessage(containsString("attribute 'bar' in annotation"));
+ exception.expectMessage(containsString("default values"));
synthesizeAnnotation(annotation);
}
@@ -927,21 +968,22 @@ public class AnnotationUtilsTests {
exception.expect(AnnotationConfigurationException.class);
exception.expectMessage(startsWith("Misconfigured aliases"));
exception.expectMessage(containsString(AliasForAttributeWithDifferentDefaultValue.class.getName()));
- exception.expectMessage(containsString("attribute [foo] in annotation"));
- exception.expectMessage(containsString("attribute [bar] in annotation"));
- exception.expectMessage(endsWith("must declare the same default value."));
+ exception.expectMessage(containsString("attribute 'foo' in annotation"));
+ exception.expectMessage(containsString("attribute 'bar' in annotation"));
+ exception.expectMessage(containsString("same default value"));
synthesizeAnnotation(annotation);
}
@Test
public void synthesizeAnnotationWithAttributeAliasForMetaAnnotationThatIsNotMetaPresent() throws Exception {
- AliasedComposedContextConfigNotMetaPresent annotation = AliasedComposedContextConfigNotMetaPresentClass.class.getAnnotation(AliasedComposedContextConfigNotMetaPresent.class);
+ AliasedComposedContextConfigNotMetaPresent annotation =
+ AliasedComposedContextConfigNotMetaPresentClass.class.getAnnotation(AliasedComposedContextConfigNotMetaPresent.class);
exception.expect(AnnotationConfigurationException.class);
- exception.expectMessage(startsWith("@AliasFor declaration on attribute [xmlConfigFile] in annotation"));
+ exception.expectMessage(startsWith("@AliasFor declaration on attribute 'xmlConfigFile' in annotation"));
exception.expectMessage(containsString(AliasedComposedContextConfigNotMetaPresent.class.getName()));
- exception.expectMessage(containsString("declares an alias for attribute [location] in meta-annotation"));
+ exception.expectMessage(containsString("declares an alias for attribute 'location' in meta-annotation"));
exception.expectMessage(containsString(ContextConfig.class.getName()));
- exception.expectMessage(endsWith("which is not meta-present."));
+ exception.expectMessage(containsString("not meta-present"));
synthesizeAnnotation(annotation);
}
@@ -956,16 +998,16 @@ public class AnnotationUtilsTests {
assertNotSame(webMapping, synthesizedWebMapping1);
assertEquals("name attribute: ", "foo", synthesizedWebMapping1.name());
- assertEquals("aliased path attribute: ", "/test", synthesizedWebMapping1.path());
- assertEquals("actual value attribute: ", "/test", synthesizedWebMapping1.value());
+ assertArrayEquals("aliased path attribute: ", asArray("/test"), synthesizedWebMapping1.path());
+ assertArrayEquals("actual value attribute: ", asArray("/test"), synthesizedWebMapping1.value());
WebMapping synthesizedWebMapping2 = synthesizeAnnotation(webMapping);
assertThat(synthesizedWebMapping2, instanceOf(SynthesizedAnnotation.class));
assertNotSame(webMapping, synthesizedWebMapping2);
assertEquals("name attribute: ", "foo", synthesizedWebMapping2.name());
- assertEquals("aliased path attribute: ", "/test", synthesizedWebMapping2.path());
- assertEquals("actual value attribute: ", "/test", synthesizedWebMapping2.value());
+ assertArrayEquals("aliased path attribute: ", asArray("/test"), synthesizedWebMapping2.path());
+ assertArrayEquals("actual value attribute: ", asArray("/test"), synthesizedWebMapping2.value());
}
@Test
@@ -990,6 +1032,31 @@ public class AnnotationUtilsTests {
}
@Test
+ public void synthesizeAnnotationWithImplicitAliasesWithImpliedAliasNamesOmitted() throws Exception {
+ assertAnnotationSynthesisWithImplicitAliasesWithImpliedAliasNamesOmitted(
+ ValueImplicitAliasesWithImpliedAliasNamesOmittedContextConfigClass.class, "value");
+ assertAnnotationSynthesisWithImplicitAliasesWithImpliedAliasNamesOmitted(
+ LocationsImplicitAliasesWithImpliedAliasNamesOmittedContextConfigClass.class, "location");
+ assertAnnotationSynthesisWithImplicitAliasesWithImpliedAliasNamesOmitted(
+ XmlFilesImplicitAliasesWithImpliedAliasNamesOmittedContextConfigClass.class, "xmlFile");
+ }
+
+ private void assertAnnotationSynthesisWithImplicitAliasesWithImpliedAliasNamesOmitted(Class<?> clazz,
+ String expected) throws Exception {
+
+ ImplicitAliasesWithImpliedAliasNamesOmittedContextConfig config = clazz.getAnnotation(
+ ImplicitAliasesWithImpliedAliasNamesOmittedContextConfig.class);
+ assertNotNull(config);
+
+ ImplicitAliasesWithImpliedAliasNamesOmittedContextConfig synthesizedConfig = synthesizeAnnotation(config);
+ assertThat(synthesizedConfig, instanceOf(SynthesizedAnnotation.class));
+
+ assertEquals("value: ", expected, synthesizedConfig.value());
+ assertEquals("locations: ", expected, synthesizedConfig.location());
+ assertEquals("xmlFiles: ", expected, synthesizedConfig.xmlFile());
+ }
+
+ @Test
public void synthesizeAnnotationWithImplicitAliasesForAliasPair() throws Exception {
Class<?> clazz = ImplicitAliasesForAliasPairContextConfigClass.class;
ImplicitAliasesForAliasPairContextConfig config = clazz.getAnnotation(ImplicitAliasesForAliasPairContextConfig.class);
@@ -1037,9 +1104,9 @@ public class AnnotationUtilsTests {
exception.expect(AnnotationConfigurationException.class);
exception.expectMessage(startsWith("Misconfigured aliases:"));
- exception.expectMessage(containsString("attribute [location1] in annotation [" + annotationType.getName() + "]"));
- exception.expectMessage(containsString("attribute [location2] in annotation [" + annotationType.getName() + "]"));
- exception.expectMessage(endsWith("must declare default values."));
+ exception.expectMessage(containsString("attribute 'location1' in annotation [" + annotationType.getName() + "]"));
+ exception.expectMessage(containsString("attribute 'location2' in annotation [" + annotationType.getName() + "]"));
+ exception.expectMessage(containsString("default values"));
synthesizeAnnotation(config, clazz);
}
@@ -1053,9 +1120,9 @@ public class AnnotationUtilsTests {
exception.expect(AnnotationConfigurationException.class);
exception.expectMessage(startsWith("Misconfigured aliases:"));
- exception.expectMessage(containsString("attribute [location1] in annotation [" + annotationType.getName() + "]"));
- exception.expectMessage(containsString("attribute [location2] in annotation [" + annotationType.getName() + "]"));
- exception.expectMessage(endsWith("must declare the same default value."));
+ exception.expectMessage(containsString("attribute 'location1' in annotation [" + annotationType.getName() + "]"));
+ exception.expectMessage(containsString("attribute 'location2' in annotation [" + annotationType.getName() + "]"));
+ exception.expectMessage(containsString("same default value"));
synthesizeAnnotation(config, clazz);
}
@@ -1077,10 +1144,9 @@ public class AnnotationUtilsTests {
exception.expectMessage(containsString(clazz.getName()));
exception.expectMessage(containsString("and synthesized from"));
exception.expectMessage(either(containsString("attribute 'location1' and its alias 'location2'")).or(
- containsString("attribute 'location2' and its alias 'location1'")));
+ containsString("attribute 'location2' and its alias 'location1'")));
exception.expectMessage(either(containsString("are present with values of [1] and [2]")).or(
- containsString("are present with values of [2] and [1]")));
- exception.expectMessage(endsWith("but only one is permitted."));
+ containsString("are present with values of [2] and [1]")));
synthesizedConfig.location1();
}
@@ -1106,8 +1172,8 @@ public class AnnotationUtilsTests {
assertNotNull(componentScan);
assertEquals("value from ComponentScan: ", "*Foo", componentScan.value().pattern());
- AnnotationAttributes attributes = getAnnotationAttributes(ComponentScanSingleFilterClass.class, componentScan,
- false, true);
+ AnnotationAttributes attributes = getAnnotationAttributes(
+ ComponentScanSingleFilterClass.class, componentScan, false, true);
assertNotNull(attributes);
assertEquals(ComponentScanSingleFilter.class, attributes.annotationType());
@@ -1119,8 +1185,8 @@ public class AnnotationUtilsTests {
filterMap.put("pattern", "newFoo");
filterMap.put("enigma", 42);
- ComponentScanSingleFilter synthesizedComponentScan = synthesizeAnnotation(attributes,
- ComponentScanSingleFilter.class, ComponentScanSingleFilterClass.class);
+ ComponentScanSingleFilter synthesizedComponentScan = synthesizeAnnotation(
+ attributes, ComponentScanSingleFilter.class, ComponentScanSingleFilterClass.class);
assertNotNull(synthesizedComponentScan);
assertNotSame(componentScan, synthesizedComponentScan);
@@ -1184,6 +1250,21 @@ public class AnnotationUtilsTests {
}
@Test
+ public void synthesizeAnnotationFromMapWithAttributeAliasesThatOverrideArraysWithSingleElements() throws Exception {
+ Map<String, Object> map = Collections.singletonMap("value", "/foo");
+ Get get = synthesizeAnnotation(map, Get.class, null);
+ assertNotNull(get);
+ assertEquals("value: ", "/foo", get.value());
+ assertEquals("path: ", "/foo", get.path());
+
+ map = Collections.singletonMap("path", "/foo");
+ get = synthesizeAnnotation(map, Get.class, null);
+ assertNotNull(get);
+ assertEquals("value: ", "/foo", get.value());
+ assertEquals("path: ", "/foo", get.path());
+ }
+
+ @Test
public void synthesizeAnnotationFromMapWithImplicitAttributeAliases() throws Exception {
assertAnnotationSynthesisFromMapWithImplicitAliases("value");
assertAnnotationSynthesisFromMapWithImplicitAliases("location1");
@@ -1220,7 +1301,7 @@ public class AnnotationUtilsTests {
private void assertMissingTextAttribute(Map<String, Object> attributes) {
exception.expect(IllegalArgumentException.class);
exception.expectMessage(startsWith("Attributes map"));
- exception.expectMessage(containsString("returned null for required attribute [text]"));
+ exception.expectMessage(containsString("returned null for required attribute 'text'"));
exception.expectMessage(containsString("defined by annotation type [" + AnnotationWithoutDefaults.class.getName() + "]"));
synthesizeAnnotation(attributes, AnnotationWithoutDefaults.class, null);
}
@@ -1232,15 +1313,15 @@ public class AnnotationUtilsTests {
exception.expect(IllegalArgumentException.class);
exception.expectMessage(startsWith("Attributes map"));
exception.expectMessage(containsString("returned a value of type [java.lang.Long]"));
- exception.expectMessage(containsString("for attribute [value]"));
+ exception.expectMessage(containsString("for attribute 'value'"));
exception.expectMessage(containsString("but a value of type [java.lang.String] is required"));
exception.expectMessage(containsString("as defined by annotation type [" + Component.class.getName() + "]"));
+
synthesizeAnnotation(map, Component.class, null);
}
@Test
public void synthesizeAnnotationFromAnnotationAttributesWithoutAttributeAliases() throws Exception {
-
// 1) Get an annotation
Component component = WebController.class.getAnnotation(Component.class);
assertNotNull(component);
@@ -1288,8 +1369,8 @@ public class AnnotationUtilsTests {
private void assertToStringForWebMappingWithPathAndValue(WebMapping webMapping) {
String string = webMapping.toString();
assertThat(string, startsWith("@" + WebMapping.class.getName() + "("));
- assertThat(string, containsString("value=/test"));
- assertThat(string, containsString("path=/test"));
+ assertThat(string, containsString("value=[/test]"));
+ assertThat(string, containsString("path=[/test]"));
assertThat(string, containsString("name=bar"));
assertThat(string, containsString("method="));
assertThat(string, containsString("[GET, POST]"));
@@ -1410,7 +1491,7 @@ public class AnnotationUtilsTests {
ContextConfig[] configs = synthesizedHierarchy.value();
assertNotNull(configs);
assertTrue("nested annotations must be synthesized",
- stream(configs).allMatch(c -> c instanceof SynthesizedAnnotation));
+ stream(configs).allMatch(c -> c instanceof SynthesizedAnnotation));
List<String> locations = stream(configs).map(ContextConfig::location).collect(toList());
assertThat(locations, is(expectedLocations));
@@ -1462,6 +1543,18 @@ public class AnnotationUtilsTests {
assertArrayEquals(new char[] { 'x', 'y', 'z' }, chars);
}
+ @SafeVarargs
+ // The following "varargs" suppression is necessary for javac from OpenJDK
+ // (1.8.0_60-b27); however, Eclipse warns that it's unnecessary. See the following
+ // Eclipse issues for details.
+ //
+ // https://bugs.eclipse.org/bugs/show_bug.cgi?id=344783
+ // https://bugs.eclipse.org/bugs/show_bug.cgi?id=349669#c10
+ // @SuppressWarnings("varargs")
+ static <T> T[] asArray(T... arr) {
+ return arr;
+ }
+
@Component("meta1")
@Order
@@ -1769,14 +1862,40 @@ public class AnnotationUtilsTests {
String name();
@AliasFor("path")
- String value() default "";
+ String[] value() default "";
@AliasFor(attribute = "value")
- String path() default "";
+ String[] path() default "";
RequestMethod[] method() default {};
}
+ /**
+ * Mock of {@code org.springframework.web.bind.annotation.GetMapping}, except
+ * that the String arrays are overridden with single String elements.
+ */
+ @Retention(RetentionPolicy.RUNTIME)
+ @WebMapping(method = RequestMethod.GET, name = "")
+ @interface Get {
+
+ @AliasFor(annotation = WebMapping.class)
+ String value() default "";
+
+ @AliasFor(annotation = WebMapping.class)
+ String path() default "";
+ }
+
+ /**
+ * Mock of {@code org.springframework.web.bind.annotation.PostMapping}, except
+ * that the path is overridden by convention with single String element.
+ */
+ @Retention(RetentionPolicy.RUNTIME)
+ @WebMapping(method = RequestMethod.POST, name = "")
+ @interface Post {
+
+ String path() default "";
+ }
+
@Component("webController")
static class WebController {
@@ -1788,6 +1907,18 @@ public class AnnotationUtilsTests {
public void handleMappedWithPathAttribute() {
}
+ @Get("/test")
+ public void getMappedWithValueAttribute() {
+ }
+
+ @Get(path = "/test")
+ public void getMappedWithPathAttribute() {
+ }
+
+ @Post(path = "/test")
+ public void postMappedWithPathAttribute() {
+ }
+
/**
* mapping is logically "equal" to handleMappedWithPathAttribute().
*/
@@ -1990,12 +2121,12 @@ public class AnnotationUtilsTests {
@ContextConfig
@Retention(RetentionPolicy.RUNTIME)
- @interface ImplicitAliasesContextConfig {
+ public @interface ImplicitAliasesContextConfig {
@AliasFor(annotation = ContextConfig.class, attribute = "location")
String xmlFile() default "";
- @AliasFor(annotation = ContextConfig.class, value = "location")
+ @AliasFor(annotation = ContextConfig.class, attribute = "location")
String groovyScript() default "";
@AliasFor(annotation = ContextConfig.class, attribute = "location")
@@ -2048,6 +2179,48 @@ public class AnnotationUtilsTests {
@ContextConfig
@Retention(RetentionPolicy.RUNTIME)
+ @interface ImplicitAliasesWithImpliedAliasNamesOmittedContextConfig {
+
+ // intentionally omitted: attribute = "value"
+ @AliasFor(annotation = ContextConfig.class)
+ String value() default "";
+
+ // intentionally omitted: attribute = "locations"
+ @AliasFor(annotation = ContextConfig.class)
+ String location() default "";
+
+ @AliasFor(annotation = ContextConfig.class, attribute = "location")
+ String xmlFile() default "";
+ }
+
+ @ImplicitAliasesWithImpliedAliasNamesOmittedContextConfig
+ @Retention(RetentionPolicy.RUNTIME)
+ @interface TransitiveImplicitAliasesWithImpliedAliasNamesOmittedContextConfig {
+
+ @AliasFor(annotation = ImplicitAliasesWithImpliedAliasNamesOmittedContextConfig.class, attribute = "xmlFile")
+ String xml() default "";
+
+ @AliasFor(annotation = ImplicitAliasesWithImpliedAliasNamesOmittedContextConfig.class, attribute = "location")
+ String groovy() default "";
+ }
+
+ // Attribute value intentionally matches attribute name:
+ @ImplicitAliasesWithImpliedAliasNamesOmittedContextConfig("value")
+ static class ValueImplicitAliasesWithImpliedAliasNamesOmittedContextConfigClass {
+ }
+
+ // Attribute value intentionally matches attribute name:
+ @ImplicitAliasesWithImpliedAliasNamesOmittedContextConfig(location = "location")
+ static class LocationsImplicitAliasesWithImpliedAliasNamesOmittedContextConfigClass {
+ }
+
+ // Attribute value intentionally matches attribute name:
+ @ImplicitAliasesWithImpliedAliasNamesOmittedContextConfig(xmlFile = "xmlFile")
+ static class XmlFilesImplicitAliasesWithImpliedAliasNamesOmittedContextConfigClass {
+ }
+
+ @ContextConfig
+ @Retention(RetentionPolicy.RUNTIME)
@interface ImplicitAliasesWithMissingDefaultValuesContextConfig {
@AliasFor(annotation = ContextConfig.class, attribute = "location")
diff --git a/spring-core/src/test/java/org/springframework/core/annotation/ComposedRepeatableAnnotationsTests.java b/spring-core/src/test/java/org/springframework/core/annotation/ComposedRepeatableAnnotationsTests.java
new file mode 100644
index 00000000..5cbc10d9
--- /dev/null
+++ b/spring-core/src/test/java/org/springframework/core/annotation/ComposedRepeatableAnnotationsTests.java
@@ -0,0 +1,386 @@
+/*
+ * Copyright 2002-2016 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 java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.AnnotatedElement;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import static org.hamcrest.CoreMatchers.isA;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.startsWith;
+import static org.junit.Assert.*;
+import static org.springframework.core.annotation.AnnotatedElementUtils.*;
+
+/**
+ * Unit tests that verify support for getting and finding all composed, repeatable
+ * annotations on a single annotated element.
+ *
+ * <p>See <a href="https://jira.spring.io/browse/SPR-13973">SPR-13973</a>.
+ *
+ * @author Sam Brannen
+ * @since 4.3
+ * @see AnnotatedElementUtils#getMergedRepeatableAnnotations
+ * @see AnnotatedElementUtils#findMergedRepeatableAnnotations
+ * @see AnnotatedElementUtilsTests
+ * @see MultipleComposedAnnotationsOnSingleAnnotatedElementTests
+ */
+public class ComposedRepeatableAnnotationsTests {
+
+ @Rule
+ public final ExpectedException exception = ExpectedException.none();
+
+
+ @Test
+ public void getNonRepeatableAnnotation() {
+ expectNonRepeatableAnnotation();
+ getMergedRepeatableAnnotations(getClass(), NonRepeatable.class);
+ }
+
+ @Test
+ public void getInvalidRepeatableAnnotationContainerMissingValueAttribute() {
+ expectContainerMissingValueAttribute();
+ getMergedRepeatableAnnotations(getClass(), InvalidRepeatable.class, ContainerMissingValueAttribute.class);
+ }
+
+ @Test
+ public void getInvalidRepeatableAnnotationContainerWithNonArrayValueAttribute() {
+ expectContainerWithNonArrayValueAttribute();
+ getMergedRepeatableAnnotations(getClass(), InvalidRepeatable.class, ContainerWithNonArrayValueAttribute.class);
+ }
+
+ @Test
+ public void getInvalidRepeatableAnnotationContainerWithArrayValueAttributeButWrongComponentType() {
+ expectContainerWithArrayValueAttributeButWrongComponentType();
+ getMergedRepeatableAnnotations(getClass(), InvalidRepeatable.class,
+ ContainerWithArrayValueAttributeButWrongComponentType.class);
+ }
+
+ @Test
+ public void getRepeatableAnnotationsOnClass() {
+ assertGetRepeatableAnnotations(RepeatableClass.class);
+ }
+
+ @Test
+ public void getRepeatableAnnotationsOnSuperclass() {
+ assertGetRepeatableAnnotations(SubRepeatableClass.class);
+ }
+
+ @Test
+ public void getComposedRepeatableAnnotationsOnClass() {
+ assertGetRepeatableAnnotations(ComposedRepeatableClass.class);
+ }
+
+ @Test
+ public void getComposedRepeatableAnnotationsMixedWithContainerOnClass() {
+ assertGetRepeatableAnnotations(ComposedRepeatableMixedWithContainerClass.class);
+ }
+
+ @Test
+ public void getComposedContainerForRepeatableAnnotationsOnClass() {
+ assertGetRepeatableAnnotations(ComposedContainerClass.class);
+ }
+
+ @Test
+ public void getNoninheritedComposedRepeatableAnnotationsOnClass() {
+ Class<?> element = NoninheritedRepeatableClass.class;
+ Set<Noninherited> annotations = getMergedRepeatableAnnotations(element, Noninherited.class);
+ assertNoninheritedRepeatableAnnotations(annotations);
+ }
+
+ @Test
+ public void getNoninheritedComposedRepeatableAnnotationsOnSuperclass() {
+ Class<?> element = SubNoninheritedRepeatableClass.class;
+ Set<Noninherited> annotations = getMergedRepeatableAnnotations(element, Noninherited.class);
+ assertNotNull(annotations);
+ assertEquals(0, annotations.size());
+ }
+
+ @Test
+ public void findNonRepeatableAnnotation() {
+ expectNonRepeatableAnnotation();
+ findMergedRepeatableAnnotations(getClass(), NonRepeatable.class);
+ }
+
+ @Test
+ public void findInvalidRepeatableAnnotationContainerMissingValueAttribute() {
+ expectContainerMissingValueAttribute();
+ findMergedRepeatableAnnotations(getClass(), InvalidRepeatable.class, ContainerMissingValueAttribute.class);
+ }
+
+ @Test
+ public void findInvalidRepeatableAnnotationContainerWithNonArrayValueAttribute() {
+ expectContainerWithNonArrayValueAttribute();
+ findMergedRepeatableAnnotations(getClass(), InvalidRepeatable.class, ContainerWithNonArrayValueAttribute.class);
+ }
+
+ @Test
+ public void findInvalidRepeatableAnnotationContainerWithArrayValueAttributeButWrongComponentType() {
+ expectContainerWithArrayValueAttributeButWrongComponentType();
+ findMergedRepeatableAnnotations(getClass(), InvalidRepeatable.class,
+ ContainerWithArrayValueAttributeButWrongComponentType.class);
+ }
+
+ @Test
+ public void findRepeatableAnnotationsOnClass() {
+ assertFindRepeatableAnnotations(RepeatableClass.class);
+ }
+
+ @Test
+ public void findRepeatableAnnotationsOnSuperclass() {
+ assertFindRepeatableAnnotations(SubRepeatableClass.class);
+ }
+
+ @Test
+ public void findComposedRepeatableAnnotationsOnClass() {
+ assertFindRepeatableAnnotations(ComposedRepeatableClass.class);
+ }
+
+ @Test
+ public void findComposedRepeatableAnnotationsMixedWithContainerOnClass() {
+ assertFindRepeatableAnnotations(ComposedRepeatableMixedWithContainerClass.class);
+ }
+
+ @Test
+ public void findNoninheritedComposedRepeatableAnnotationsOnClass() {
+ Class<?> element = NoninheritedRepeatableClass.class;
+ Set<Noninherited> annotations = findMergedRepeatableAnnotations(element, Noninherited.class);
+ assertNoninheritedRepeatableAnnotations(annotations);
+ }
+
+ @Test
+ public void findNoninheritedComposedRepeatableAnnotationsOnSuperclass() {
+ Class<?> element = SubNoninheritedRepeatableClass.class;
+ Set<Noninherited> annotations = findMergedRepeatableAnnotations(element, Noninherited.class);
+ assertNoninheritedRepeatableAnnotations(annotations);
+ }
+
+ @Test
+ public void findComposedContainerForRepeatableAnnotationsOnClass() {
+ assertFindRepeatableAnnotations(ComposedContainerClass.class);
+ }
+
+ private void expectNonRepeatableAnnotation() {
+ exception.expect(IllegalArgumentException.class);
+ exception.expectMessage(startsWith("annotationType must be a repeatable annotation"));
+ exception.expectMessage(containsString("failed to resolve container type for"));
+ exception.expectMessage(containsString(NonRepeatable.class.getName()));
+ }
+
+ private void expectContainerMissingValueAttribute() {
+ exception.expect(AnnotationConfigurationException.class);
+ exception.expectMessage(startsWith("Invalid declaration of container type"));
+ exception.expectMessage(containsString(ContainerMissingValueAttribute.class.getName()));
+ exception.expectMessage(containsString("for repeatable annotation"));
+ exception.expectMessage(containsString(InvalidRepeatable.class.getName()));
+ exception.expectCause(isA(NoSuchMethodException.class));
+ }
+
+ private void expectContainerWithNonArrayValueAttribute() {
+ exception.expect(AnnotationConfigurationException.class);
+ exception.expectMessage(startsWith("Container type"));
+ exception.expectMessage(containsString(ContainerWithNonArrayValueAttribute.class.getName()));
+ exception.expectMessage(containsString("must declare a 'value' attribute for an array of type"));
+ exception.expectMessage(containsString(InvalidRepeatable.class.getName()));
+ }
+
+ private void expectContainerWithArrayValueAttributeButWrongComponentType() {
+ exception.expect(AnnotationConfigurationException.class);
+ exception.expectMessage(startsWith("Container type"));
+ exception.expectMessage(containsString(ContainerWithArrayValueAttributeButWrongComponentType.class.getName()));
+ exception.expectMessage(containsString("must declare a 'value' attribute for an array of type"));
+ exception.expectMessage(containsString(InvalidRepeatable.class.getName()));
+ }
+
+ private void assertGetRepeatableAnnotations(AnnotatedElement element) {
+ assertNotNull(element);
+
+ Set<PeteRepeat> peteRepeats = getMergedRepeatableAnnotations(element, PeteRepeat.class);
+ assertNotNull(peteRepeats);
+ assertEquals(3, peteRepeats.size());
+
+ Iterator<PeteRepeat> iterator = peteRepeats.iterator();
+ assertEquals("A", iterator.next().value());
+ assertEquals("B", iterator.next().value());
+ assertEquals("C", iterator.next().value());
+ }
+
+ private void assertFindRepeatableAnnotations(AnnotatedElement element) {
+ assertNotNull(element);
+
+ Set<PeteRepeat> peteRepeats = findMergedRepeatableAnnotations(element, PeteRepeat.class);
+ assertNotNull(peteRepeats);
+ assertEquals(3, peteRepeats.size());
+
+ Iterator<PeteRepeat> iterator = peteRepeats.iterator();
+ assertEquals("A", iterator.next().value());
+ assertEquals("B", iterator.next().value());
+ assertEquals("C", iterator.next().value());
+ }
+
+ private void assertNoninheritedRepeatableAnnotations(Set<Noninherited> annotations) {
+ assertNotNull(annotations);
+ assertEquals(3, annotations.size());
+
+ Iterator<Noninherited> iterator = annotations.iterator();
+ assertEquals("A", iterator.next().value());
+ assertEquals("B", iterator.next().value());
+ assertEquals("C", iterator.next().value());
+ }
+
+
+ // -------------------------------------------------------------------------
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @interface NonRepeatable {
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @interface ContainerMissingValueAttribute {
+ // InvalidRepeatable[] value();
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @interface ContainerWithNonArrayValueAttribute {
+
+ InvalidRepeatable value();
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @interface ContainerWithArrayValueAttributeButWrongComponentType {
+
+ String[] value();
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @interface InvalidRepeatable {
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @Inherited
+ @interface PeteRepeats {
+
+ PeteRepeat[] value();
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @Inherited
+ @Repeatable(PeteRepeats.class)
+ @interface PeteRepeat {
+
+ String value();
+ }
+
+ @PeteRepeat("shadowed")
+ @Target({ ElementType.METHOD, ElementType.TYPE })
+ @Retention(RetentionPolicy.RUNTIME)
+ @Inherited
+ @interface ForPetesSake {
+
+ @AliasFor(annotation = PeteRepeat.class)
+ String value();
+ }
+
+ @PeteRepeat("shadowed")
+ @Target({ ElementType.METHOD, ElementType.TYPE })
+ @Retention(RetentionPolicy.RUNTIME)
+ @Inherited
+ @interface ForTheLoveOfFoo {
+
+ @AliasFor(annotation = PeteRepeat.class)
+ String value();
+ }
+
+ @PeteRepeats({ @PeteRepeat("B"), @PeteRepeat("C") })
+ @Target({ ElementType.METHOD, ElementType.TYPE })
+ @Retention(RetentionPolicy.RUNTIME)
+ @Inherited
+ @interface ComposedContainer {
+ }
+
+ @PeteRepeat("A")
+ @PeteRepeats({ @PeteRepeat("B"), @PeteRepeat("C") })
+ static class RepeatableClass {
+ }
+
+ static class SubRepeatableClass extends RepeatableClass {
+ }
+
+ @ForPetesSake("B")
+ @ForTheLoveOfFoo("C")
+ @PeteRepeat("A")
+ static class ComposedRepeatableClass {
+ }
+
+ @ForPetesSake("C")
+ @PeteRepeats(@PeteRepeat("A"))
+ @PeteRepeat("B")
+ static class ComposedRepeatableMixedWithContainerClass {
+ }
+
+ @PeteRepeat("A")
+ @ComposedContainer
+ static class ComposedContainerClass {
+ }
+
+ @Target(ElementType.TYPE)
+ @Retention(RetentionPolicy.RUNTIME)
+ @interface Noninheriteds {
+
+ Noninherited[] value();
+ }
+
+ @Target(ElementType.TYPE)
+ @Retention(RetentionPolicy.RUNTIME)
+ @Repeatable(Noninheriteds.class)
+ @interface Noninherited {
+
+ @AliasFor("name")
+ String value() default "";
+
+ @AliasFor("value")
+ String name() default "";
+ }
+
+ @Noninherited(name = "shadowed")
+ @Target(ElementType.TYPE)
+ @Retention(RetentionPolicy.RUNTIME)
+ @interface ComposedNoninherited {
+
+ @AliasFor(annotation = Noninherited.class)
+ String name() default "";
+ }
+
+ @ComposedNoninherited(name = "C")
+ @Noninheriteds({ @Noninherited(value = "A"), @Noninherited(name = "B") })
+ static class NoninheritedRepeatableClass {
+ }
+
+ static class SubNoninheritedRepeatableClass extends NoninheritedRepeatableClass {
+ }
+
+}
diff --git a/spring-core/src/test/java/org/springframework/core/annotation/MapAnnotationAttributeExtractorTests.java b/spring-core/src/test/java/org/springframework/core/annotation/MapAnnotationAttributeExtractorTests.java
index a3811527..d3b45602 100644
--- a/spring-core/src/test/java/org/springframework/core/annotation/MapAnnotationAttributeExtractorTests.java
+++ b/spring-core/src/test/java/org/springframework/core/annotation/MapAnnotationAttributeExtractorTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2015 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -26,11 +26,14 @@ import org.junit.Before;
import org.junit.Test;
import org.springframework.core.annotation.AnnotationUtilsTests.ImplicitAliasesContextConfig;
+import org.springframework.core.annotation.AnnotationUtilsTests.RequestMethod;
+import org.springframework.core.annotation.AnnotationUtilsTests.WebMapping;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
+import static org.springframework.core.annotation.AnnotationUtilsTests.*;
/**
* Unit tests for {@link MapAnnotationAttributeExtractor}.
@@ -38,6 +41,7 @@ import static org.junit.Assert.*;
* @author Sam Brannen
* @since 4.2.1
*/
+@SuppressWarnings("serial")
public class MapAnnotationAttributeExtractorTests extends AbstractAliasAwareAnnotationAttributeExtractorTestCase {
@Before
@@ -46,7 +50,6 @@ public class MapAnnotationAttributeExtractorTests extends AbstractAliasAwareAnno
}
@Test
- @SuppressWarnings("serial")
public void enrichAndValidateAttributesWithImplicitAliasesAndMinimalAttributes() {
Map<String, Object> attributes = new HashMap<String, Object>();
Map<String, Object> expectedAttributes = new HashMap<String, Object>() {{
@@ -64,7 +67,6 @@ public class MapAnnotationAttributeExtractorTests extends AbstractAliasAwareAnno
}
@Test
- @SuppressWarnings("serial")
public void enrichAndValidateAttributesWithImplicitAliases() {
Map<String, Object> attributes = new HashMap<String, Object>() {{
put("groovyScript", "groovy!");
@@ -84,6 +86,31 @@ public class MapAnnotationAttributeExtractorTests extends AbstractAliasAwareAnno
assertEnrichAndValidateAttributes(attributes, expectedAttributes);
}
+ @Test
+ public void enrichAndValidateAttributesWithSingleElementThatOverridesAnArray() {
+ // @formatter:off
+ Map<String, Object> attributes = new HashMap<String, Object>() {{
+ // Intentionally storing 'value' as a single String instead of an array.
+ // put("value", asArray("/foo"));
+ put("value", "/foo");
+ put("name", "test");
+ }};
+
+ Map<String, Object> expected = new HashMap<String, Object>() {{
+ put("value", asArray("/foo"));
+ put("path", asArray("/foo"));
+ put("name", "test");
+ put("method", new RequestMethod[0]);
+ }};
+ // @formatter:on
+
+ MapAnnotationAttributeExtractor extractor = new MapAnnotationAttributeExtractor(attributes, WebMapping.class, null);
+ Map<String, Object> enriched = extractor.getSource();
+
+ assertEquals("attribute map size", expected.size(), enriched.size());
+ expected.forEach((attr, expectedValue) -> assertThat("for attribute '" + attr + "'", enriched.get(attr), is(expectedValue)));
+ }
+
@SuppressWarnings("unchecked")
private void assertEnrichAndValidateAttributes(Map<String, Object> sourceAttributes, Map<String, Object> expected) {
Class<? extends Annotation> annotationType = ImplicitAliasesContextConfig.class;
@@ -114,8 +141,7 @@ public class MapAnnotationAttributeExtractorTests extends AbstractAliasAwareAnno
Map<String, Object> enriched = extractor.getSource();
assertEquals("attribute map size", expected.size(), enriched.size());
- expected.keySet().stream().forEach( attr ->
- assertThat("for attribute '" + attr + "'", enriched.get(attr), is(expected.get(attr))));
+ expected.forEach((attr, expectedValue) -> assertThat("for attribute '" + attr + "'", enriched.get(attr), is(expectedValue)));
}
@Override
diff --git a/spring-core/src/test/java/org/springframework/core/annotation/MultipleComposedAnnotationsOnSingleAnnotatedElementTests.java b/spring-core/src/test/java/org/springframework/core/annotation/MultipleComposedAnnotationsOnSingleAnnotatedElementTests.java
new file mode 100644
index 00000000..fc2259ac
--- /dev/null
+++ b/spring-core/src/test/java/org/springframework/core/annotation/MultipleComposedAnnotationsOnSingleAnnotatedElementTests.java
@@ -0,0 +1,368 @@
+/*
+ * Copyright 2002-2016 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 java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Method;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.junit.Ignore;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+import static org.springframework.core.annotation.AnnotatedElementUtils.*;
+
+/**
+ * Unit tests that verify support for finding multiple composed annotations on
+ * a single annotated element.
+ *
+ * <p>See <a href="https://jira.spring.io/browse/SPR-13486">SPR-13486</a>.
+ *
+ * @author Sam Brannen
+ * @since 4.3
+ * @see AnnotatedElementUtils
+ * @see AnnotatedElementUtilsTests
+ * @see ComposedRepeatableAnnotationsTests
+ */
+public class MultipleComposedAnnotationsOnSingleAnnotatedElementTests {
+
+ @Test
+ public void getMultipleComposedAnnotationsOnClass() {
+ assertGetAllMergedAnnotationsBehavior(MultipleComposedCachesClass.class);
+ }
+
+ @Test
+ public void getMultipleInheritedComposedAnnotationsOnSuperclass() {
+ assertGetAllMergedAnnotationsBehavior(SubMultipleComposedCachesClass.class);
+ }
+
+ @Test
+ public void getMultipleNoninheritedComposedAnnotationsOnClass() {
+ Class<?> element = MultipleNoninheritedComposedCachesClass.class;
+ Set<Cacheable> cacheables = getAllMergedAnnotations(element, Cacheable.class);
+ assertNotNull(cacheables);
+ assertEquals(2, cacheables.size());
+
+ Iterator<Cacheable> iterator = cacheables.iterator();
+ Cacheable cacheable1 = iterator.next();
+ Cacheable cacheable2 = iterator.next();
+ assertEquals("noninheritedCache1", cacheable1.value());
+ assertEquals("noninheritedCache2", cacheable2.value());
+ }
+
+ @Test
+ public void getMultipleNoninheritedComposedAnnotationsOnSuperclass() {
+ Class<?> element = SubMultipleNoninheritedComposedCachesClass.class;
+ Set<Cacheable> cacheables = getAllMergedAnnotations(element, Cacheable.class);
+ assertNotNull(cacheables);
+ assertEquals(0, cacheables.size());
+ }
+
+ @Test
+ public void getComposedPlusLocalAnnotationsOnClass() {
+ assertGetAllMergedAnnotationsBehavior(ComposedPlusLocalCachesClass.class);
+ }
+
+ @Test
+ public void getMultipleComposedAnnotationsOnInterface() {
+ Class<MultipleComposedCachesOnInterfaceClass> element = MultipleComposedCachesOnInterfaceClass.class;
+ Set<Cacheable> cacheables = getAllMergedAnnotations(element, Cacheable.class);
+ assertNotNull(cacheables);
+ assertEquals(0, cacheables.size());
+ }
+
+ @Test
+ public void getMultipleComposedAnnotationsOnMethod() throws Exception {
+ AnnotatedElement element = getClass().getDeclaredMethod("multipleComposedCachesMethod");
+ assertGetAllMergedAnnotationsBehavior(element);
+ }
+
+ @Test
+ public void getComposedPlusLocalAnnotationsOnMethod() throws Exception {
+ AnnotatedElement element = getClass().getDeclaredMethod("composedPlusLocalCachesMethod");
+ assertGetAllMergedAnnotationsBehavior(element);
+ }
+
+ @Test
+ @Ignore("Disabled since some Java 8 updates handle the bridge method differently")
+ public void getMultipleComposedAnnotationsOnBridgeMethod() throws Exception {
+ Set<Cacheable> cacheables = getAllMergedAnnotations(getBridgeMethod(), Cacheable.class);
+ assertNotNull(cacheables);
+ assertEquals(0, cacheables.size());
+ }
+
+ @Test
+ public void findMultipleComposedAnnotationsOnClass() {
+ assertFindAllMergedAnnotationsBehavior(MultipleComposedCachesClass.class);
+ }
+
+ @Test
+ public void findMultipleInheritedComposedAnnotationsOnSuperclass() {
+ assertFindAllMergedAnnotationsBehavior(SubMultipleComposedCachesClass.class);
+ }
+
+ @Test
+ public void findMultipleNoninheritedComposedAnnotationsOnClass() {
+ Class<?> element = MultipleNoninheritedComposedCachesClass.class;
+ Set<Cacheable> cacheables = findAllMergedAnnotations(element, Cacheable.class);
+ assertNotNull(cacheables);
+ assertEquals(2, cacheables.size());
+
+ Iterator<Cacheable> iterator = cacheables.iterator();
+ Cacheable cacheable1 = iterator.next();
+ Cacheable cacheable2 = iterator.next();
+ assertEquals("noninheritedCache1", cacheable1.value());
+ assertEquals("noninheritedCache2", cacheable2.value());
+ }
+
+ @Test
+ public void findMultipleNoninheritedComposedAnnotationsOnSuperclass() {
+ Class<?> element = SubMultipleNoninheritedComposedCachesClass.class;
+ Set<Cacheable> cacheables = findAllMergedAnnotations(element, Cacheable.class);
+ assertNotNull(cacheables);
+ assertEquals(2, cacheables.size());
+
+ Iterator<Cacheable> iterator = cacheables.iterator();
+ Cacheable cacheable1 = iterator.next();
+ Cacheable cacheable2 = iterator.next();
+ assertEquals("noninheritedCache1", cacheable1.value());
+ assertEquals("noninheritedCache2", cacheable2.value());
+ }
+
+ @Test
+ public void findComposedPlusLocalAnnotationsOnClass() {
+ assertFindAllMergedAnnotationsBehavior(ComposedPlusLocalCachesClass.class);
+ }
+
+ @Test
+ public void findMultipleComposedAnnotationsOnInterface() {
+ assertFindAllMergedAnnotationsBehavior(MultipleComposedCachesOnInterfaceClass.class);
+ }
+
+ @Test
+ public void findComposedCacheOnInterfaceAndLocalCacheOnClass() {
+ assertFindAllMergedAnnotationsBehavior(ComposedCacheOnInterfaceAndLocalCacheClass.class);
+ }
+
+ @Test
+ public void findMultipleComposedAnnotationsOnMethod() throws Exception {
+ AnnotatedElement element = getClass().getDeclaredMethod("multipleComposedCachesMethod");
+ assertFindAllMergedAnnotationsBehavior(element);
+ }
+
+ @Test
+ public void findComposedPlusLocalAnnotationsOnMethod() throws Exception {
+ AnnotatedElement element = getClass().getDeclaredMethod("composedPlusLocalCachesMethod");
+ assertFindAllMergedAnnotationsBehavior(element);
+ }
+
+ @Test
+ public void findMultipleComposedAnnotationsOnBridgeMethod() throws Exception {
+ assertFindAllMergedAnnotationsBehavior(getBridgeMethod());
+ }
+
+ /**
+ * Bridge/bridged method setup code copied from
+ * {@link org.springframework.core.BridgeMethodResolverTests#testWithGenericParameter()}.
+ */
+ public Method getBridgeMethod() throws NoSuchMethodException {
+ Method[] methods = StringGenericParameter.class.getMethods();
+ Method bridgeMethod = null;
+ Method bridgedMethod = null;
+
+ for (Method method : methods) {
+ if ("getFor".equals(method.getName()) && !method.getParameterTypes()[0].equals(Integer.class)) {
+ if (method.getReturnType().equals(Object.class)) {
+ bridgeMethod = method;
+ }
+ else {
+ bridgedMethod = method;
+ }
+ }
+ }
+ assertTrue(bridgeMethod != null && bridgeMethod.isBridge());
+ assertTrue(bridgedMethod != null && !bridgedMethod.isBridge());
+
+ return bridgeMethod;
+ }
+
+ private void assertGetAllMergedAnnotationsBehavior(AnnotatedElement element) {
+ assertNotNull(element);
+
+ Set<Cacheable> cacheables = getAllMergedAnnotations(element, Cacheable.class);
+ assertNotNull(cacheables);
+ assertEquals(2, cacheables.size());
+
+ Iterator<Cacheable> iterator = cacheables.iterator();
+ Cacheable fooCacheable = iterator.next();
+ Cacheable barCacheable = iterator.next();
+ assertEquals("fooKey", fooCacheable.key());
+ assertEquals("fooCache", fooCacheable.value());
+ assertEquals("barKey", barCacheable.key());
+ assertEquals("barCache", barCacheable.value());
+ }
+
+ private void assertFindAllMergedAnnotationsBehavior(AnnotatedElement element) {
+ assertNotNull(element);
+
+ Set<Cacheable> cacheables = findAllMergedAnnotations(element, Cacheable.class);
+ assertNotNull(cacheables);
+ assertEquals(2, cacheables.size());
+
+ Iterator<Cacheable> iterator = cacheables.iterator();
+ Cacheable fooCacheable = iterator.next();
+ Cacheable barCacheable = iterator.next();
+ assertEquals("fooKey", fooCacheable.key());
+ assertEquals("fooCache", fooCacheable.value());
+ assertEquals("barKey", barCacheable.key());
+ assertEquals("barCache", barCacheable.value());
+ }
+
+
+ // -------------------------------------------------------------------------
+
+ /**
+ * Mock of {@code org.springframework.cache.annotation.Cacheable}.
+ */
+ @Target({ ElementType.METHOD, ElementType.TYPE })
+ @Retention(RetentionPolicy.RUNTIME)
+ @Inherited
+ @interface Cacheable {
+
+ @AliasFor("cacheName")
+ String value() default "";
+
+ @AliasFor("value")
+ String cacheName() default "";
+
+ String key() default "";
+ }
+
+ @Cacheable("fooCache")
+ @Target({ ElementType.METHOD, ElementType.TYPE })
+ @Retention(RetentionPolicy.RUNTIME)
+ @Inherited
+ @interface FooCache {
+
+ @AliasFor(annotation = Cacheable.class)
+ String key() default "";
+ }
+
+ @Cacheable("barCache")
+ @Target({ ElementType.METHOD, ElementType.TYPE })
+ @Retention(RetentionPolicy.RUNTIME)
+ @Inherited
+ @interface BarCache {
+
+ @AliasFor(annotation = Cacheable.class)
+ String key();
+ }
+
+ @Cacheable("noninheritedCache1")
+ @Target({ ElementType.METHOD, ElementType.TYPE })
+ @Retention(RetentionPolicy.RUNTIME)
+ @interface NoninheritedCache1 {
+
+ @AliasFor(annotation = Cacheable.class)
+ String key() default "";
+ }
+
+ @Cacheable("noninheritedCache2")
+ @Target({ ElementType.METHOD, ElementType.TYPE })
+ @Retention(RetentionPolicy.RUNTIME)
+ @interface NoninheritedCache2 {
+
+ @AliasFor(annotation = Cacheable.class)
+ String key() default "";
+ }
+
+ @FooCache(key = "fooKey")
+ @BarCache(key = "barKey")
+ private static class MultipleComposedCachesClass {
+ }
+
+ private static class SubMultipleComposedCachesClass extends MultipleComposedCachesClass {
+ }
+
+ @NoninheritedCache1
+ @NoninheritedCache2
+ private static class MultipleNoninheritedComposedCachesClass {
+ }
+
+ private static class SubMultipleNoninheritedComposedCachesClass extends MultipleNoninheritedComposedCachesClass {
+ }
+
+ @Cacheable(cacheName = "fooCache", key = "fooKey")
+ @BarCache(key = "barKey")
+ private static class ComposedPlusLocalCachesClass {
+ }
+
+ @FooCache(key = "fooKey")
+ @BarCache(key = "barKey")
+ private interface MultipleComposedCachesInterface {
+ }
+
+ private static class MultipleComposedCachesOnInterfaceClass implements MultipleComposedCachesInterface {
+ }
+
+ @Cacheable(cacheName = "fooCache", key = "fooKey")
+ private interface ComposedCacheInterface {
+ }
+
+ @BarCache(key = "barKey")
+ private static class ComposedCacheOnInterfaceAndLocalCacheClass implements ComposedCacheInterface {
+ }
+
+
+ @FooCache(key = "fooKey")
+ @BarCache(key = "barKey")
+ private void multipleComposedCachesMethod() {
+ }
+
+ @Cacheable(cacheName = "fooCache", key = "fooKey")
+ @BarCache(key = "barKey")
+ private void composedPlusLocalCachesMethod() {
+ }
+
+
+ public interface GenericParameter<T> {
+
+ T getFor(Class<T> cls);
+ }
+
+ @SuppressWarnings("unused")
+ private static class StringGenericParameter implements GenericParameter<String> {
+
+ @FooCache(key = "fooKey")
+ @BarCache(key = "barKey")
+ @Override
+ public String getFor(Class<String> cls) {
+ return "foo";
+ }
+
+ public String getFor(Integer integer) {
+ return "foo";
+ }
+ }
+
+}
diff --git a/spring-core/src/test/java/org/springframework/core/convert/TypeDescriptorTests.java b/spring-core/src/test/java/org/springframework/core/convert/TypeDescriptorTests.java
index 61f30c31..39184c2c 100644
--- a/spring-core/src/test/java/org/springframework/core/convert/TypeDescriptorTests.java
+++ b/spring-core/src/test/java/org/springframework/core/convert/TypeDescriptorTests.java
@@ -52,27 +52,11 @@ import static org.junit.Assert.*;
* @author Andy Clement
* @author Phillip Webb
* @author Sam Brannen
+ * @author Nathan Piper
*/
@SuppressWarnings("rawtypes")
public class TypeDescriptorTests {
- public List<String> listOfString;
-
- public List<List<String>> listOfListOfString = new ArrayList<List<String>>();
-
- public List<List> listOfListOfUnknown = new ArrayList<List>();
-
- public int[] intArray;
-
- public List<String>[] arrayOfListOfString;
-
- public List<Integer> listField = new ArrayList<Integer>();
-
- public Map<String, Integer> mapField = new HashMap<String, Integer>();
-
- public Map<String, List<Integer>> nestedMapField = new HashMap<String, List<Integer>>();
-
-
@Test
public void parameterPrimitive() throws Exception {
TypeDescriptor desc = new TypeDescriptor(new MethodParameter(getClass().getMethod("testParameterPrimitive", int.class), 0));
@@ -86,10 +70,6 @@ public class TypeDescriptorTests {
assertFalse(desc.isMap());
}
- public void testParameterPrimitive(int primitive) {
-
- }
-
@Test
public void parameterScalar() throws Exception {
TypeDescriptor desc = new TypeDescriptor(new MethodParameter(getClass().getMethod("testParameterScalar", String.class), 0));
@@ -104,10 +84,6 @@ public class TypeDescriptorTests {
assertFalse(desc.isMap());
}
- public void testParameterScalar(String value) {
-
- }
-
@Test
public void parameterList() throws Exception {
MethodParameter methodParameter = new MethodParameter(getClass().getMethod("testParameterList", List.class), 0);
@@ -129,10 +105,6 @@ public class TypeDescriptorTests {
assertFalse(desc.isMap());
}
- public void testParameterList(List<List<Map<Integer, Enum<?>>>> list) {
-
- }
-
@Test
public void parameterListNoParamTypes() throws Exception {
MethodParameter methodParameter = new MethodParameter(getClass().getMethod("testParameterListNoParamTypes", List.class), 0);
@@ -149,10 +121,6 @@ public class TypeDescriptorTests {
assertFalse(desc.isMap());
}
- public void testParameterListNoParamTypes(List list) {
-
- }
-
@Test
public void parameterArray() throws Exception {
MethodParameter methodParameter = new MethodParameter(getClass().getMethod("testParameterArray", Integer[].class), 0);
@@ -170,10 +138,6 @@ public class TypeDescriptorTests {
assertFalse(desc.isMap());
}
- public void testParameterArray(Integer[] array) {
-
- }
-
@Test
public void parameterMap() throws Exception {
MethodParameter methodParameter = new MethodParameter(getClass().getMethod("testParameterMap", Map.class), 0);
@@ -194,10 +158,6 @@ public class TypeDescriptorTests {
assertEquals(String.class, desc.getMapValueTypeDescriptor().getElementTypeDescriptor().getType());
}
- public void testParameterMap(Map<Integer, List<String>> map) {
-
- }
-
@Test
public void parameterAnnotated() throws Exception {
TypeDescriptor t1 = new TypeDescriptor(new MethodParameter(getClass().getMethod("testAnnotatedMethod", String.class), 0));
@@ -208,36 +168,20 @@ public class TypeDescriptorTests {
assertEquals(123, t1.getAnnotation(ParameterAnnotation.class).value());
}
- @Target({ElementType.PARAMETER})
- @Retention(RetentionPolicy.RUNTIME)
- public @interface ParameterAnnotation {
- int value();
- }
-
- public void testAnnotatedMethod(@ParameterAnnotation(123) String parameter) {
-
- }
-
@Test
public void propertyComplex() throws Exception {
- Property property = new Property(getClass(), getClass().getMethod("getComplexProperty"), getClass().getMethod("setComplexProperty", Map.class));
+ Property property = new Property(getClass(), getClass().getMethod("getComplexProperty"),
+ getClass().getMethod("setComplexProperty", Map.class));
TypeDescriptor desc = new TypeDescriptor(property);
assertEquals(String.class, desc.getMapKeyTypeDescriptor().getType());
assertEquals(Integer.class, desc.getMapValueTypeDescriptor().getElementTypeDescriptor().getElementTypeDescriptor().getType());
}
- public Map<String, List<List<Integer>>> getComplexProperty() {
- return null;
- }
-
- public void setComplexProperty(Map<String, List<List<Integer>>> complexProperty) {
-
- }
-
@Test
public void propertyGenericType() throws Exception {
GenericType<Integer> genericBean = new IntegerType();
- Property property = new Property(getClass(), genericBean.getClass().getMethod("getProperty"), genericBean.getClass().getMethod("setProperty", Integer.class));
+ Property property = new Property(getClass(), genericBean.getClass().getMethod("getProperty"),
+ genericBean.getClass().getMethod("setProperty", Integer.class));
TypeDescriptor desc = new TypeDescriptor(property);
assertEquals(Integer.class, desc.getType());
}
@@ -245,7 +189,8 @@ public class TypeDescriptorTests {
@Test
public void propertyTypeCovariance() throws Exception {
GenericType<Number> genericBean = new NumberType();
- Property property = new Property(getClass(), genericBean.getClass().getMethod("getProperty"), genericBean.getClass().getMethod("setProperty", Number.class));
+ Property property = new Property(getClass(), genericBean.getClass().getMethod("getProperty"),
+ genericBean.getClass().getMethod("setProperty", Number.class));
TypeDescriptor desc = new TypeDescriptor(property);
assertEquals(Integer.class, desc.getType());
}
@@ -253,69 +198,18 @@ public class TypeDescriptorTests {
@Test
public void propertyGenericTypeList() throws Exception {
GenericType<Integer> genericBean = new IntegerType();
- Property property = new Property(getClass(), genericBean.getClass().getMethod("getListProperty"), genericBean.getClass().getMethod("setListProperty", List.class));
+ Property property = new Property(getClass(), genericBean.getClass().getMethod("getListProperty"),
+ genericBean.getClass().getMethod("setListProperty", List.class));
TypeDescriptor desc = new TypeDescriptor(property);
assertEquals(List.class, desc.getType());
assertEquals(Integer.class, desc.getElementTypeDescriptor().getType());
}
- public interface GenericType<T> {
- T getProperty();
-
- void setProperty(T t);
-
- List<T> getListProperty();
-
- void setListProperty(List<T> t);
-
- }
-
- public class IntegerType implements GenericType<Integer> {
-
- @Override
- public Integer getProperty() {
- return null;
- }
-
- @Override
- public void setProperty(Integer t) {
- }
-
- @Override
- public List<Integer> getListProperty() {
- return null;
- }
-
- @Override
- public void setListProperty(List<Integer> t) {
- }
- }
-
- public class NumberType implements GenericType<Number> {
-
- @Override
- public Integer getProperty() {
- return null;
- }
-
- @Override
- public void setProperty(Number t) {
- }
-
- @Override
- public List<Number> getListProperty() {
- return null;
- }
-
- @Override
- public void setListProperty(List<Number> t) {
- }
- }
-
@Test
public void propertyGenericClassList() throws Exception {
IntegerClass genericBean = new IntegerClass();
- Property property = new Property(genericBean.getClass(), genericBean.getClass().getMethod("getListProperty"), genericBean.getClass().getMethod("setListProperty", List.class));
+ Property property = new Property(genericBean.getClass(), genericBean.getClass().getMethod("getListProperty"),
+ genericBean.getClass().getMethod("setListProperty", List.class));
TypeDescriptor desc = new TypeDescriptor(property);
assertEquals(List.class, desc.getType());
assertEquals(Integer.class, desc.getElementTypeDescriptor().getType());
@@ -323,32 +217,10 @@ public class TypeDescriptorTests {
assertTrue(desc.hasAnnotation(MethodAnnotation1.class));
}
- public static class GenericClass<T> {
-
- public T getProperty() {
- return null;
- }
-
- public void setProperty(T t) {
- }
-
- @MethodAnnotation1
- public List<T> getListProperty() {
- return null;
- }
-
- public void setListProperty(List<T> t) {
- }
-
- }
-
- public static class IntegerClass extends GenericClass<Integer> {
-
- }
-
@Test
public void property() throws Exception {
- Property property = new Property(getClass(), getClass().getMethod("getProperty"), getClass().getMethod("setProperty", Map.class));
+ Property property = new Property(
+ getClass(), getClass().getMethod("getProperty"), getClass().getMethod("setProperty", Map.class));
TypeDescriptor desc = new TypeDescriptor(property);
assertEquals(Map.class, desc.getType());
assertEquals(Integer.class, desc.getMapKeyTypeDescriptor().getElementTypeDescriptor().getType());
@@ -358,60 +230,6 @@ public class TypeDescriptorTests {
assertNotNull(desc.getAnnotation(MethodAnnotation3.class));
}
- @MethodAnnotation1
- public Map<List<Integer>, List<Long>> getProperty() {
- return property;
- }
-
- @MethodAnnotation2
- public void setProperty(Map<List<Integer>, List<Long>> property) {
- this.property = property;
- }
-
- @MethodAnnotation3
- private Map<List<Integer>, List<Long>> property;
-
-
- @Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
- @Retention(RetentionPolicy.RUNTIME)
- public @interface MethodAnnotation1 {
- }
-
- @Target({ElementType.METHOD})
- @Retention(RetentionPolicy.RUNTIME)
- public @interface MethodAnnotation2 {
- }
-
- @Target({ElementType.FIELD})
- @Retention(RetentionPolicy.RUNTIME)
- public @interface MethodAnnotation3 {
- }
-
- @MethodAnnotation1
- @Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
- @Retention(RetentionPolicy.RUNTIME)
- public @interface ComposedMethodAnnotation1 {}
-
- @ComposedMethodAnnotation1
- @Target(ElementType.METHOD)
- @Retention(RetentionPolicy.RUNTIME)
- public @interface ComposedComposedMethodAnnotation1 {}
-
- @MethodAnnotation1
- public void methodWithLocalAnnotation() {}
-
- @ComposedMethodAnnotation1
- public void methodWithComposedAnnotation() {}
-
- @ComposedComposedMethodAnnotation1
- public void methodWithComposedComposedAnnotation() {}
-
- private void assertAnnotationFoundOnMethod(Class<? extends Annotation> annotationType, String methodName) throws Exception {
- TypeDescriptor typeDescriptor = new TypeDescriptor(new MethodParameter(getClass().getMethod(methodName), -1));
- assertNotNull("Should have found @" + annotationType.getSimpleName() + " on " + methodName + ".",
- typeDescriptor.getAnnotation(annotationType));
- }
-
@Test
public void getAnnotationOnMethodThatIsLocallyAnnotated() throws Exception {
assertAnnotationFoundOnMethod(MethodAnnotation1.class, "methodWithLocalAnnotation");
@@ -427,6 +245,12 @@ public class TypeDescriptorTests {
assertAnnotationFoundOnMethod(MethodAnnotation1.class, "methodWithComposedComposedAnnotation");
}
+ private void assertAnnotationFoundOnMethod(Class<? extends Annotation> annotationType, String methodName) throws Exception {
+ TypeDescriptor typeDescriptor = new TypeDescriptor(new MethodParameter(getClass().getMethod(methodName), -1));
+ assertNotNull("Should have found @" + annotationType.getSimpleName() + " on " + methodName + ".",
+ typeDescriptor.getAnnotation(annotationType));
+ }
+
@Test
public void fieldScalar() throws Exception {
TypeDescriptor typeDescriptor = new TypeDescriptor(getClass().getField("fieldScalar"));
@@ -438,8 +262,6 @@ public class TypeDescriptorTests {
assertEquals(Integer.class, typeDescriptor.getObjectType());
}
- public Integer fieldScalar;
-
@Test
public void fieldList() throws Exception {
TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("listOfString"));
@@ -504,8 +326,6 @@ public class TypeDescriptorTests {
assertEquals(Long.class, desc.getMapValueTypeDescriptor().getElementTypeDescriptor().getType());
}
- public Map<List<Integer>, List<Long>> fieldMap;
-
@Test
public void fieldAnnotated() throws Exception {
TypeDescriptor typeDescriptor = new TypeDescriptor(getClass().getField("fieldAnnotated"));
@@ -513,15 +333,6 @@ public class TypeDescriptorTests {
assertNotNull(typeDescriptor.getAnnotation(FieldAnnotation.class));
}
- @FieldAnnotation
- public List<String> fieldAnnotated;
-
- @Target({ElementType.FIELD})
- @Retention(RetentionPolicy.RUNTIME)
- public @interface FieldAnnotation {
-
- }
-
@Test
public void valueOfScalar() {
TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(Integer.class);
@@ -592,7 +403,7 @@ public class TypeDescriptorTests {
assertEquals(String.class, t1.getType());
}
- @Test(expected=IllegalArgumentException.class)
+ @Test(expected = IllegalArgumentException.class)
public void nestedMethodParameterNot1NestedLevel() throws Exception {
TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test4", List.class), 0, 2), 2);
}
@@ -609,31 +420,11 @@ public class TypeDescriptorTests {
assertNull(t1);
}
- @Test(expected=IllegalArgumentException.class)
+ @Test(expected = IllegalArgumentException.class)
public void nestedMethodParameterTypeInvalidNestingLevel() throws Exception {
TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test5", String.class), 0, 2), 2);
}
- public void test1(List<String> param1) {
-
- }
-
- public void test2(List<List<String>> param1) {
-
- }
-
- public void test3(Map<Integer, String> param1) {
-
- }
-
- public void test4(List<Map<Integer, String>> param1) {
-
- }
-
- public void test5(String param1) {
-
- }
-
@Test
public void nestedNotParameterized() throws Exception {
TypeDescriptor t1 = TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test6", List.class), 0), 1);
@@ -643,18 +434,12 @@ public class TypeDescriptorTests {
assertNull(t2);
}
- public void test6(List<List> param1) {
-
- }
-
@Test
public void nestedFieldTypeMapTwoLevels() throws Exception {
TypeDescriptor t1 = TypeDescriptor.nested(getClass().getField("test4"), 2);
assertEquals(String.class, t1.getType());
}
- public List<Map<Integer, String>> test4;
-
@Test
public void nestedPropertyTypeMapTwoLevels() throws Exception {
Property property = new Property(getClass(), getClass().getMethod("getTest4"), getClass().getMethod("setTest4", List.class));
@@ -662,14 +447,6 @@ public class TypeDescriptorTests {
assertEquals(String.class, t1.getType());
}
- public List<Map<Integer, String>> getTest4() {
- return null;
- }
-
- public void setTest4(List<Map<Integer, String>> test4) {
-
- }
-
@Test
public void collection() {
TypeDescriptor desc = TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Integer.class));
@@ -762,9 +539,6 @@ public class TypeDescriptorTests {
assertNotNull(desc.getAnnotation(FieldAnnotation.class));
}
- @FieldAnnotation
- public List<List<Integer>> listPreserveContext;
-
@Test
public void mapKeyType() {
TypeDescriptor desc = TypeDescriptor.valueOf(Map.class);
@@ -783,9 +557,6 @@ public class TypeDescriptorTests {
assertNotNull(desc.getAnnotation(FieldAnnotation.class));
}
- @FieldAnnotation
- public Map<List<Integer>, List<Integer>> mapPreserveContext;
-
@Test
public void mapValueType() {
TypeDescriptor desc = TypeDescriptor.valueOf(Map.class);
@@ -805,7 +576,7 @@ public class TypeDescriptorTests {
}
@Test
- public void equals() throws Exception {
+ public void equality() throws Exception {
TypeDescriptor t1 = TypeDescriptor.valueOf(String.class);
TypeDescriptor t2 = TypeDescriptor.valueOf(String.class);
TypeDescriptor t3 = TypeDescriptor.valueOf(Date.class);
@@ -826,6 +597,18 @@ public class TypeDescriptorTests {
TypeDescriptor t11 = new TypeDescriptor(getClass().getField("mapField"));
TypeDescriptor t12 = new TypeDescriptor(getClass().getField("mapField"));
assertEquals(t11, t12);
+
+ TypeDescriptor t13 = new TypeDescriptor(new MethodParameter(getClass().getMethod("testAnnotatedMethod", String.class), 0));
+ TypeDescriptor t14 = new TypeDescriptor(new MethodParameter(getClass().getMethod("testAnnotatedMethod", String.class), 0));
+ assertEquals(t13, t14);
+
+ TypeDescriptor t15 = new TypeDescriptor(new MethodParameter(getClass().getMethod("testAnnotatedMethod", String.class), 0));
+ TypeDescriptor t16 = new TypeDescriptor(new MethodParameter(getClass().getMethod("testAnnotatedMethodDifferentAnnotationValue", String.class), 0));
+ assertNotEquals(t15, t16);
+
+ TypeDescriptor t17 = new TypeDescriptor(new MethodParameter(getClass().getMethod("testAnnotatedMethod", String.class), 0));
+ TypeDescriptor t18 = new TypeDescriptor(new MethodParameter(getClass().getMethod("test5", String.class), 0));
+ assertNotEquals(t17, t18);
}
@Test
@@ -844,10 +627,6 @@ public class TypeDescriptorTests {
assertTrue(TypeDescriptor.valueOf(List.class).isAssignableTo(new TypeDescriptor(getClass().getField("listField"))));
}
- public List notGenericList;
-
- public List<Number> isAssignableElementTypes;
-
@Test
public void isAssignableMapKeyValueTypes() throws Exception {
assertTrue(new TypeDescriptor(getClass().getField("mapField")).isAssignableTo(new TypeDescriptor(getClass().getField("mapField"))));
@@ -857,10 +636,6 @@ public class TypeDescriptorTests {
assertTrue(TypeDescriptor.valueOf(Map.class).isAssignableTo(new TypeDescriptor(getClass().getField("mapField"))));
}
- public Map notGenericMap;
-
- public Map<CharSequence, Number> isAssignableMapKeyValueTypes;
-
@Test
public void multiValueMap() throws Exception {
TypeDescriptor td = new TypeDescriptor(getClass().getField("multiValueMap"));
@@ -871,8 +646,6 @@ public class TypeDescriptorTests {
td.getMapValueTypeDescriptor().getElementTypeDescriptor().getType());
}
- public MultiValueMap<String, Integer> multiValueMap = new LinkedMultiValueMap<String, Integer>();
-
@Test
public void passDownGeneric() throws Exception {
TypeDescriptor td = new TypeDescriptor(getClass().getField("passDownGeneric"));
@@ -881,12 +654,6 @@ public class TypeDescriptorTests {
assertEquals(Integer.class, td.getElementTypeDescriptor().getElementTypeDescriptor().getElementTypeDescriptor().getType());
}
- public PassDownGeneric<Integer> passDownGeneric = new PassDownGeneric<Integer>();
-
- @SuppressWarnings("serial")
- public static class PassDownGeneric<T> extends ArrayList<List<Set<T>>> {
- }
-
@Test
public void testUpCast() throws Exception {
Property property = new Property(getClass(), getClass().getMethod("getProperty"),
@@ -904,8 +671,9 @@ public class TypeDescriptorTests {
try {
typeDescriptor.upcast(Collection.class);
fail("Did not throw");
- } catch(IllegalArgumentException e) {
- assertEquals("interface java.util.Map is not assignable to interface java.util.Collection", e.getMessage());
+ }
+ catch (IllegalArgumentException ex) {
+ assertEquals("interface java.util.Map is not assignable to interface java.util.Collection", ex.getMessage());
}
}
@@ -933,13 +701,13 @@ public class TypeDescriptorTests {
@Test
public void createMapArray() throws Exception {
- TypeDescriptor mapType = TypeDescriptor.map(LinkedHashMap.class, TypeDescriptor.valueOf(String.class), TypeDescriptor.valueOf(Integer.class));
+ TypeDescriptor mapType = TypeDescriptor.map(
+ LinkedHashMap.class, TypeDescriptor.valueOf(String.class), TypeDescriptor.valueOf(Integer.class));
TypeDescriptor arrayType = TypeDescriptor.array(mapType);
assertEquals(arrayType.getType(), LinkedHashMap[].class);
assertEquals(arrayType.getElementTypeDescriptor(), mapType);
}
-
@Test
public void createStringArray() throws Exception {
TypeDescriptor arrayType = TypeDescriptor.array(TypeDescriptor.valueOf(String.class));
@@ -985,4 +753,268 @@ public class TypeDescriptorTests {
assertThat(TypeDescriptor.valueOf(Integer.class).getSource(), equalTo((Object) Integer.class));
}
+
+ // Methods designed for test introspection
+
+ public void testParameterPrimitive(int primitive) {
+ }
+
+ public void testParameterScalar(String value) {
+ }
+
+ public void testParameterList(List<List<Map<Integer, Enum<?>>>> list) {
+ }
+
+ public void testParameterListNoParamTypes(List list) {
+ }
+
+ public void testParameterArray(Integer[] array) {
+ }
+
+ public void testParameterMap(Map<Integer, List<String>> map) {
+ }
+
+ public void test1(List<String> param1) {
+ }
+
+ public void test2(List<List<String>> param1) {
+ }
+
+ public void test3(Map<Integer, String> param1) {
+ }
+
+ public void test4(List<Map<Integer, String>> param1) {
+ }
+
+ public void test5(String param1) {
+ }
+
+ public void test6(List<List> param1) {
+ }
+
+ public List<Map<Integer, String>> getTest4() {
+ return null;
+ }
+
+ public void setTest4(List<Map<Integer, String>> test4) {
+ }
+
+ public Map<String, List<List<Integer>>> getComplexProperty() {
+ return null;
+ }
+
+ @MethodAnnotation1
+ public Map<List<Integer>, List<Long>> getProperty() {
+ return property;
+ }
+
+ @MethodAnnotation2
+ public void setProperty(Map<List<Integer>, List<Long>> property) {
+ this.property = property;
+ }
+
+ @MethodAnnotation1
+ public void methodWithLocalAnnotation() {
+ }
+
+ @ComposedMethodAnnotation1
+ public void methodWithComposedAnnotation() {
+ }
+
+ @ComposedComposedMethodAnnotation1
+ public void methodWithComposedComposedAnnotation() {
+ }
+
+ public void setComplexProperty(Map<String, List<List<Integer>>> complexProperty) {
+ }
+
+ public void testAnnotatedMethod(@ParameterAnnotation(123) String parameter) {
+ }
+
+ public void testAnnotatedMethodDifferentAnnotationValue(@ParameterAnnotation(567) String parameter) {
+ }
+
+
+ // Fields designed for test introspection
+
+ public Integer fieldScalar;
+
+ public List<String> listOfString;
+
+ public List<List<String>> listOfListOfString = new ArrayList<List<String>>();
+
+ public List<List> listOfListOfUnknown = new ArrayList<List>();
+
+ public int[] intArray;
+
+ public List<String>[] arrayOfListOfString;
+
+ public List<Integer> listField = new ArrayList<Integer>();
+
+ public Map<String, Integer> mapField = new HashMap<String, Integer>();
+
+ public Map<String, List<Integer>> nestedMapField = new HashMap<String, List<Integer>>();
+
+ public Map<List<Integer>, List<Long>> fieldMap;
+
+ public List<Map<Integer, String>> test4;
+
+ @FieldAnnotation
+ public List<String> fieldAnnotated;
+
+ @FieldAnnotation
+ public List<List<Integer>> listPreserveContext;
+
+ @FieldAnnotation
+ public Map<List<Integer>, List<Integer>> mapPreserveContext;
+
+ @MethodAnnotation3
+ private Map<List<Integer>, List<Long>> property;
+
+ public List notGenericList;
+
+ public List<Number> isAssignableElementTypes;
+
+ public Map notGenericMap;
+
+ public Map<CharSequence, Number> isAssignableMapKeyValueTypes;
+
+ public MultiValueMap<String, Integer> multiValueMap = new LinkedMultiValueMap<String, Integer>();
+
+ public PassDownGeneric<Integer> passDownGeneric = new PassDownGeneric<Integer>();
+
+
+ // Classes designed for test introspection
+
+ @SuppressWarnings("serial")
+ public static class PassDownGeneric<T> extends ArrayList<List<Set<T>>> {
+ }
+
+
+ public static class GenericClass<T> {
+
+ public T getProperty() {
+ return null;
+ }
+
+ public void setProperty(T t) {
+ }
+
+ @MethodAnnotation1
+ public List<T> getListProperty() {
+ return null;
+ }
+
+ public void setListProperty(List<T> t) {
+ }
+ }
+
+
+ public static class IntegerClass extends GenericClass<Integer> {
+ }
+
+
+ public interface GenericType<T> {
+
+ T getProperty();
+
+ void setProperty(T t);
+
+ List<T> getListProperty();
+
+ void setListProperty(List<T> t);
+ }
+
+
+ public class IntegerType implements GenericType<Integer> {
+
+ @Override
+ public Integer getProperty() {
+ return null;
+ }
+
+ @Override
+ public void setProperty(Integer t) {
+ }
+
+ @Override
+ public List<Integer> getListProperty() {
+ return null;
+ }
+
+ @Override
+ public void setListProperty(List<Integer> t) {
+ }
+ }
+
+
+ public class NumberType implements GenericType<Number> {
+
+ @Override
+ public Integer getProperty() {
+ return null;
+ }
+
+ @Override
+ public void setProperty(Number t) {
+ }
+
+ @Override
+ public List<Number> getListProperty() {
+ return null;
+ }
+
+ @Override
+ public void setListProperty(List<Number> t) {
+ }
+ }
+
+
+ // Annotations used on tested elements
+
+ @Target({ElementType.PARAMETER})
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface ParameterAnnotation {
+
+ int value();
+ }
+
+
+ @Target({ElementType.FIELD})
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface FieldAnnotation {
+ }
+
+
+ @Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface MethodAnnotation1 {
+ }
+
+
+ @Target({ElementType.METHOD})
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface MethodAnnotation2 {
+ }
+
+
+ @Target({ElementType.FIELD})
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface MethodAnnotation3 {
+ }
+
+
+ @MethodAnnotation1
+ @Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface ComposedMethodAnnotation1 {
+ }
+
+
+ @ComposedMethodAnnotation1
+ @Target(ElementType.METHOD)
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface ComposedComposedMethodAnnotation1 {
+ }
+
}
diff --git a/spring-core/src/test/java/org/springframework/core/convert/support/CollectionToCollectionConverterTests.java b/spring-core/src/test/java/org/springframework/core/convert/support/CollectionToCollectionConverterTests.java
index c65ba7d3..131e739e 100644
--- a/spring-core/src/test/java/org/springframework/core/convert/support/CollectionToCollectionConverterTests.java
+++ b/spring-core/src/test/java/org/springframework/core/convert/support/CollectionToCollectionConverterTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2015 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -75,10 +75,10 @@ public class CollectionToCollectionConverterTests {
conversionService.addConverterFactory(new StringToNumberConverterFactory());
assertTrue(conversionService.canConvert(sourceType, targetType));
@SuppressWarnings("unchecked")
- List<String> result = (List<String>) conversionService.convert(list, sourceType, targetType);
+ List<Integer> result = (List<Integer>) conversionService.convert(list, sourceType, targetType);
assertFalse(list.equals(result));
- assertEquals(9, result.get(0));
- assertEquals(37, result.get(1));
+ assertEquals(9, result.get(0).intValue());
+ assertEquals(37, result.get(1).intValue());
}
@Test
@@ -262,6 +262,25 @@ public class CollectionToCollectionConverterTests {
}
+ public ArrayList<Integer> scalarListTarget;
+
+ public List<Integer> emptyListTarget;
+
+ public LinkedList<Integer> emptyListDifferentTarget;
+
+ public List<List<List<Integer>>> objectToCollection;
+
+ public List<String> strings;
+
+ public List<?> list = Collections.emptyList();
+
+ public Collection<?> wildcardCollection = Collections.emptyList();
+
+ public List<Resource> resources;
+
+ public EnumSet<MyEnum> enumSet;
+
+
public static abstract class BaseResource implements Resource {
@Override
@@ -330,25 +349,6 @@ public class CollectionToCollectionConverterTests {
}
- public static enum MyEnum {A, B, C}
-
-
- public ArrayList<Integer> scalarListTarget;
-
- public List<Integer> emptyListTarget;
-
- public LinkedList<Integer> emptyListDifferentTarget;
-
- public List<List<List<Integer>>> objectToCollection;
-
- public List<String> strings;
-
- public List<?> list = Collections.emptyList();
-
- public Collection<?> wildcardCollection = Collections.emptyList();
-
- public List<Resource> resources;
-
- public EnumSet<MyEnum> enumSet;
+ public enum MyEnum {A, B, C}
}
diff --git a/spring-core/src/test/java/org/springframework/core/convert/support/DefaultConversionServiceTests.java b/spring-core/src/test/java/org/springframework/core/convert/support/DefaultConversionServiceTests.java
index 5059738c..e7caf78b 100644
--- a/spring-core/src/test/java/org/springframework/core/convert/support/DefaultConversionServiceTests.java
+++ b/spring-core/src/test/java/org/springframework/core/convert/support/DefaultConversionServiceTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2015 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -243,6 +243,26 @@ public class DefaultConversionServiceTests {
public void testEnumToString() {
assertEquals("BAR", conversionService.convert(Foo.BAR, String.class));
}
+
+ @Test
+ public void testIntegerToEnum() throws Exception {
+ assertEquals(Foo.BAR, conversionService.convert(0, Foo.class));
+ }
+
+ @Test
+ public void testIntegerToEnumWithSubclass() throws Exception {
+ assertEquals(SubFoo.BAZ, conversionService.convert(1, SubFoo.BAR.getClass()));
+ }
+
+ @Test
+ public void testIntegerToEnumNull() {
+ assertEquals(null, conversionService.convert(null, Foo.class));
+ }
+
+ @Test
+ public void testEnumToInteger() {
+ assertEquals(Integer.valueOf(0), conversionService.convert(Foo.BAR, Integer.class));
+ }
@Test
public void testStringToEnumSet() throws Exception {
@@ -313,7 +333,7 @@ public class DefaultConversionServiceTests {
@Test
public void convertArrayToCollectionInterface() {
- List<?> result = conversionService.convert(new String[] { "1", "2", "3" }, List.class);
+ List<?> result = conversionService.convert(new String[] {"1", "2", "3"}, List.class);
assertEquals("1", result.get(0));
assertEquals("2", result.get(1));
assertEquals("3", result.get(2));
@@ -322,7 +342,7 @@ public class DefaultConversionServiceTests {
@Test
public void convertArrayToCollectionGenericTypeConversion() throws Exception {
@SuppressWarnings("unchecked")
- List<Integer> result = (List<Integer>) conversionService.convert(new String[] { "1", "2", "3" }, TypeDescriptor
+ List<Integer> result = (List<Integer>) conversionService.convert(new String[] {"1", "2", "3"}, TypeDescriptor
.valueOf(String[].class), new TypeDescriptor(getClass().getDeclaredField("genericList")));
assertEquals(new Integer("1"), result.get(0));
assertEquals(new Integer("2"), result.get(1));
@@ -344,7 +364,7 @@ public class DefaultConversionServiceTests {
ConverterRegistry registry = (conversionService);
registry.addConverter(new ColorConverter());
@SuppressWarnings("unchecked")
- List<Color> colors = (List<Color>) conversionService.convert(new String[] { "ffffff", "#000000" },
+ List<Color> colors = (List<Color>) conversionService.convert(new String[] {"ffffff", "#000000"},
TypeDescriptor.valueOf(String[].class),
new TypeDescriptor(new MethodParameter(getClass().getMethod("handlerMethod", List.class), 0)));
assertEquals(2, colors.size());
@@ -354,7 +374,7 @@ public class DefaultConversionServiceTests {
@Test
public void convertArrayToCollectionImpl() {
- LinkedList<?> result = conversionService.convert(new String[] { "1", "2", "3" }, LinkedList.class);
+ LinkedList<?> result = conversionService.convert(new String[] {"1", "2", "3"}, LinkedList.class);
assertEquals("1", result.get(0));
assertEquals("2", result.get(1));
assertEquals("3", result.get(2));
@@ -371,13 +391,13 @@ public class DefaultConversionServiceTests {
@Test
public void convertArrayToString() {
- String result = conversionService.convert(new String[] { "1", "2", "3" }, String.class);
+ String result = conversionService.convert(new String[] {"1", "2", "3"}, String.class);
assertEquals("1,2,3", result);
}
@Test
public void convertArrayToStringWithElementConversion() {
- String result = conversionService.convert(new Integer[] { 1, 2, 3 }, String.class);
+ String result = conversionService.convert(new Integer[] {1, 2, 3}, String.class);
assertEquals("1,2,3", result);
}
@@ -422,21 +442,21 @@ public class DefaultConversionServiceTests {
@Test
public void convertArrayToObject() {
- Object[] array = new Object[] { 3L };
+ Object[] array = new Object[] {3L};
Object result = conversionService.convert(array, Long.class);
assertEquals(3L, result);
}
@Test
public void convertArrayToObjectWithElementConversion() {
- String[] array = new String[] { "3" };
+ String[] array = new String[] {"3"};
Integer result = conversionService.convert(array, Integer.class);
assertEquals(new Integer(3), result);
}
@Test
public void convertArrayToObjectAssignableTargetType() {
- Long[] array = new Long[] { 3L };
+ Long[] array = new Long[] {3L};
Long[] result = (Long[]) conversionService.convert(array, Object.class);
assertArrayEquals(array, result);
}
@@ -561,9 +581,9 @@ public class DefaultConversionServiceTests {
}
@Test
- @SuppressWarnings("unchecked")
+ @SuppressWarnings("rawtypes")
public void convertObjectToCollection() {
- List<String> result = (List<String>) conversionService.convert(3L, List.class);
+ List result = conversionService.convert(3L, List.class);
assertEquals(1, result.size());
assertEquals(3L, result.get(0));
}
@@ -849,14 +869,14 @@ public class DefaultConversionServiceTests {
}
});
char[] converted = conversionService.convert("abc", char[].class);
- assertThat(converted, equalTo(new char[] { 'a', 'b', 'c' }));
+ assertThat(converted, equalTo(new char[] {'a', 'b', 'c'}));
}
@Test
@SuppressWarnings("unchecked")
public void multidimensionalArrayToListConversionShouldConvertEntriesCorrectly() {
- String[][] grid = new String[][] { new String[] { "1", "2", "3", "4" }, new String[] { "5", "6", "7", "8" },
- new String[] { "9", "10", "11", "12" } };
+ String[][] grid = new String[][] {new String[] {"1", "2", "3", "4"}, new String[] {"5", "6", "7", "8"},
+ new String[] {"9", "10", "11", "12"}};
List<String[]> converted = conversionService.convert(grid, List.class);
String[][] convertedBack = conversionService.convert(converted, String[][].class);
assertArrayEquals(grid, convertedBack);
@@ -865,16 +885,15 @@ public class DefaultConversionServiceTests {
@Test
public void convertCannotOptimizeArray() {
conversionService.addConverter(new Converter<Byte, Byte>() {
-
@Override
public Byte convert(Byte source) {
return (byte) (source + 1);
}
});
- byte[] byteArray = new byte[] { 1, 2, 3 };
+ byte[] byteArray = new byte[] {1, 2, 3};
byte[] converted = conversionService.convert(byteArray, byte[].class);
assertNotSame(byteArray, converted);
- assertTrue(Arrays.equals(new byte[] { 2, 3, 4 }, converted));
+ assertTrue(Arrays.equals(new byte[] {2, 3, 4}, converted));
}
@Test
@@ -938,6 +957,7 @@ public class DefaultConversionServiceTests {
public enum Foo {
+
BAR, BAZ
}
@@ -964,7 +984,12 @@ public class DefaultConversionServiceTests {
public class ColorConverter implements Converter<String, Color> {
@Override
- public Color convert(String source) { if (!source.startsWith("#")) source = "#" + source; return Color.decode(source); }
+ public Color convert(String source) {
+ if (!source.startsWith("#")) {
+ source = "#" + source;
+ }
+ return Color.decode(source);
+ }
}
@@ -1031,8 +1056,8 @@ public class DefaultConversionServiceTests {
private static class SSN {
static int constructorCount = 0;
- static int toStringCount = 0;
+ static int toStringCount = 0;
static void reset() {
constructorCount = 0;
diff --git a/spring-core/src/test/java/org/springframework/core/convert/support/GenericConversionServiceTests.java b/spring-core/src/test/java/org/springframework/core/convert/support/GenericConversionServiceTests.java
index 6b16aefe..4b3183b6 100644
--- a/spring-core/src/test/java/org/springframework/core/convert/support/GenericConversionServiceTests.java
+++ b/spring-core/src/test/java/org/springframework/core/convert/support/GenericConversionServiceTests.java
@@ -479,6 +479,21 @@ public class GenericConversionServiceTests {
}
@Test
+ public void conditionalConverterCachingForDifferentAnnotationAttributes() throws Exception {
+ conversionService.addConverter(new ColorConverter());
+ conversionService.addConverter(new MyConditionalColorConverter());
+
+ assertEquals(Color.BLACK, conversionService.convert("000000xxxx",
+ new TypeDescriptor(getClass().getField("activeColor"))));
+ assertEquals(Color.BLACK, conversionService.convert(" #000000 ",
+ new TypeDescriptor(getClass().getField("inactiveColor"))));
+ assertEquals(Color.BLACK, conversionService.convert("000000yyyy",
+ new TypeDescriptor(getClass().getField("activeColor"))));
+ assertEquals(Color.BLACK, conversionService.convert(" #000000 ",
+ new TypeDescriptor(getClass().getField("inactiveColor"))));
+ }
+
+ @Test
public void shouldNotSupportNullConvertibleTypesFromNonConditionalGenericConverter() {
GenericConverter converter = new NonConditionalGenericConverter();
try {
@@ -629,14 +644,49 @@ public class GenericConversionServiceTests {
}
+ @ExampleAnnotation(active = true)
+ public String annotatedString;
+
+ @ExampleAnnotation(active = true)
+ public Color activeColor;
+
+ @ExampleAnnotation(active = false)
+ public Color inactiveColor;
+
+ public List<Integer> list;
+
+ public Map<String, Integer> map;
+
+ public Map<String, ?> wildcardMap;
+
+ @SuppressWarnings("rawtypes")
+ public Collection rawCollection;
+
+ public Collection<?> genericCollection;
+
+ public Collection<String> stringCollection;
+
+ public Collection<Integer> integerCollection;
+
+
@Retention(RetentionPolicy.RUNTIME)
- private static @interface ExampleAnnotation {}
+ private @interface ExampleAnnotation {
+
+ boolean active();
+ }
+
+
+ private interface MyBaseInterface {
+ }
- private static interface MyBaseInterface {}
- private static interface MyInterface extends MyBaseInterface {}
+ private interface MyInterface extends MyBaseInterface {
+ }
+
+
+ private static class MyInterfaceImplementer implements MyInterface {
+ }
- private static class MyInterfaceImplementer implements MyInterface {}
private static class MyBaseInterfaceToStringConverter implements Converter<MyBaseInterface, String> {
@@ -646,6 +696,7 @@ public class GenericConversionServiceTests {
}
}
+
private static class MyStringArrayToResourceArrayConverter implements Converter<String[], Resource[]> {
@Override
@@ -654,6 +705,7 @@ public class GenericConversionServiceTests {
}
}
+
private static class MyStringArrayToIntegerArrayConverter implements Converter<String[], Integer[]> {
@Override
@@ -662,6 +714,7 @@ public class GenericConversionServiceTests {
}
}
+
private static class MyStringToIntegerArrayConverter implements Converter<String, Integer[]> {
@Override
@@ -671,6 +724,7 @@ public class GenericConversionServiceTests {
}
}
+
private static class WithCopyConstructor {
WithCopyConstructor() {}
@@ -679,6 +733,7 @@ public class GenericConversionServiceTests {
WithCopyConstructor(WithCopyConstructor value) {}
}
+
private static class MyConditionalConverter implements Converter<String, Color>, ConditionalConverter {
private int matchAttempts = 0;
@@ -699,6 +754,7 @@ public class GenericConversionServiceTests {
}
}
+
private static class NonConditionalGenericConverter implements GenericConverter {
@Override
@@ -712,6 +768,7 @@ public class GenericConversionServiceTests {
}
}
+
private static class MyConditionalGenericConverter implements GenericConverter, ConditionalConverter {
private final List<TypeDescriptor> sourceTypes = new ArrayList<TypeDescriptor>();
@@ -737,6 +794,7 @@ public class GenericConversionServiceTests {
}
}
+
private static class MyConditionalConverterFactory implements ConverterFactory<String, Color>, ConditionalConverter {
private MyConditionalConverter converter = new MyConditionalConverter();
@@ -768,11 +826,13 @@ public class GenericConversionServiceTests {
String getBaseCode();
}
- private static interface MyEnumInterface extends MyEnumBaseInterface {
+
+ private interface MyEnumInterface extends MyEnumBaseInterface {
String getCode();
}
- private static enum MyEnum implements MyEnumInterface {
+
+ private enum MyEnum implements MyEnumInterface {
A("1"),
B("2"),
@@ -795,7 +855,8 @@ public class GenericConversionServiceTests {
}
}
- private static enum EnumWithSubclass {
+
+ private enum EnumWithSubclass {
FIRST {
@Override
@@ -805,6 +866,7 @@ public class GenericConversionServiceTests {
}
}
+
@SuppressWarnings("rawtypes")
private static class MyStringToRawCollectionConverter implements Converter<String, Collection> {
@@ -814,6 +876,7 @@ public class GenericConversionServiceTests {
}
}
+
private static class MyStringToGenericCollectionConverter implements Converter<String, Collection<?>> {
@Override
@@ -822,6 +885,7 @@ public class GenericConversionServiceTests {
}
}
+
private static class MyEnumInterfaceToStringConverter<T extends MyEnumInterface> implements Converter<T, String> {
@Override
@@ -830,14 +894,16 @@ public class GenericConversionServiceTests {
}
}
+
private static class StringToMyEnumInterfaceConverterFactory implements ConverterFactory<String, MyEnumInterface> {
- @SuppressWarnings({ "unchecked", "rawtypes" })
+ @SuppressWarnings({"unchecked", "rawtypes"})
public <T extends MyEnumInterface> Converter<String, T> getConverter(Class<T> targetType) {
return new StringToMyEnumInterfaceConverter(targetType);
}
private static class StringToMyEnumInterfaceConverter<T extends Enum<?> & MyEnumInterface> implements Converter<String, T> {
+
private final Class<T> enumType;
public StringToMyEnumInterfaceConverter(Class<T> enumType) {
@@ -855,9 +921,10 @@ public class GenericConversionServiceTests {
}
}
+
private static class StringToMyEnumBaseInterfaceConverterFactory implements ConverterFactory<String, MyEnumBaseInterface> {
- @SuppressWarnings({ "unchecked", "rawtypes" })
+ @SuppressWarnings({"unchecked", "rawtypes"})
public <T extends MyEnumBaseInterface> Converter<String, T> getConverter(Class<T> targetType) {
return new StringToMyEnumBaseInterfaceConverter(targetType);
}
@@ -881,6 +948,7 @@ public class GenericConversionServiceTests {
}
}
+
private static class MyStringToStringCollectionConverter implements Converter<String, Collection<String>> {
@Override
@@ -889,6 +957,7 @@ public class GenericConversionServiceTests {
}
}
+
private static class MyStringToIntegerCollectionConverter implements Converter<String, Collection<Integer>> {
@Override
@@ -897,6 +966,7 @@ public class GenericConversionServiceTests {
}
}
+
@SuppressWarnings("rawtypes")
private static class UntypedConverter implements Converter {
@@ -906,28 +976,27 @@ public class GenericConversionServiceTests {
}
}
+
private static class ColorConverter implements Converter<String, Color> {
+
@Override
- public Color convert(String source) { if (!source.startsWith("#")) source = "#" + source; return Color.decode(source); }
+ public Color convert(String source) {
+ return Color.decode(source.trim());
+ }
}
- @ExampleAnnotation
- public String annotatedString;
-
- public List<Integer> list;
-
- public Map<String, Integer> map;
-
- public Map<String, ?> wildcardMap;
-
- @SuppressWarnings("rawtypes")
- public Collection rawCollection;
-
- public Collection<?> genericCollection;
-
- public Collection<String> stringCollection;
+ private static class MyConditionalColorConverter implements Converter<String, Color>, ConditionalConverter {
- public Collection<Integer> integerCollection;
+ @Override
+ public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
+ ExampleAnnotation ann = targetType.getAnnotation(ExampleAnnotation.class);
+ return (ann != null && ann.active());
+ }
+ @Override
+ public Color convert(String source) {
+ return Color.decode(source.substring(0, 6));
+ }
+ }
}
diff --git a/spring-core/src/test/java/org/springframework/core/convert/support/MapToMapConverterTests.java b/spring-core/src/test/java/org/springframework/core/convert/support/MapToMapConverterTests.java
index 510f4f53..3757f554 100644
--- a/spring-core/src/test/java/org/springframework/core/convert/support/MapToMapConverterTests.java
+++ b/spring-core/src/test/java/org/springframework/core/convert/support/MapToMapConverterTests.java
@@ -36,9 +36,14 @@ import org.springframework.util.MultiValueMap;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
+/**
+ * @author Keith Donald
+ * @author Phil Webb
+ * @author Juergen Hoeller
+ */
public class MapToMapConverterTests {
- private GenericConversionService conversionService = new GenericConversionService();
+ private final GenericConversionService conversionService = new GenericConversionService();
@Before
@@ -54,12 +59,15 @@ public class MapToMapConverterTests {
map.put("2", "37");
TypeDescriptor sourceType = TypeDescriptor.forObject(map);
TypeDescriptor targetType = new TypeDescriptor(getClass().getField("scalarMapTarget"));
+
assertTrue(conversionService.canConvert(sourceType, targetType));
try {
conversionService.convert(map, sourceType, targetType);
- } catch (ConversionFailedException e) {
- assertTrue(e.getCause() instanceof ConverterNotFoundException);
}
+ catch (ConversionFailedException ex) {
+ assertTrue(ex.getCause() instanceof ConverterNotFoundException);
+ }
+
conversionService.addConverterFactory(new StringToNumberConverterFactory());
assertTrue(conversionService.canConvert(sourceType, targetType));
@SuppressWarnings("unchecked")
@@ -74,6 +82,7 @@ public class MapToMapConverterTests {
Map<String, String> map = new HashMap<String, String>();
map.put("1", "9");
map.put("2", "37");
+
assertTrue(conversionService.canConvert(Map.class, Map.class));
assertSame(map, conversionService.convert(map, Map.class));
}
@@ -85,12 +94,15 @@ public class MapToMapConverterTests {
map.put("2", "37");
TypeDescriptor sourceType = new TypeDescriptor(getClass().getField("notGenericMapSource"));
TypeDescriptor targetType = new TypeDescriptor(getClass().getField("scalarMapTarget"));
+
assertTrue(conversionService.canConvert(sourceType, targetType));
try {
conversionService.convert(map, sourceType, targetType);
- } catch (ConversionFailedException e) {
- assertTrue(e.getCause() instanceof ConverterNotFoundException);
}
+ catch (ConversionFailedException ex) {
+ assertTrue(ex.getCause() instanceof ConverterNotFoundException);
+ }
+
conversionService.addConverterFactory(new StringToNumberConverterFactory());
assertTrue(conversionService.canConvert(sourceType, targetType));
@SuppressWarnings("unchecked")
@@ -107,12 +119,15 @@ public class MapToMapConverterTests {
map.put("2", Arrays.asList("37", "23"));
TypeDescriptor sourceType = TypeDescriptor.forObject(map);
TypeDescriptor targetType = new TypeDescriptor(getClass().getField("collectionMapTarget"));
+
assertTrue(conversionService.canConvert(sourceType, targetType));
try {
conversionService.convert(map, sourceType, targetType);
- } catch (ConversionFailedException e) {
- assertTrue(e.getCause() instanceof ConverterNotFoundException);
}
+ catch (ConversionFailedException ex) {
+ assertTrue(ex.getCause() instanceof ConverterNotFoundException);
+ }
+
conversionService.addConverter(new CollectionToCollectionConverter(conversionService));
conversionService.addConverterFactory(new StringToNumberConverterFactory());
assertTrue(conversionService.canConvert(sourceType, targetType));
@@ -130,6 +145,7 @@ public class MapToMapConverterTests {
map.put("2", Arrays.asList("37", "23"));
TypeDescriptor sourceType = new TypeDescriptor(getClass().getField("sourceCollectionMapTarget"));
TypeDescriptor targetType = new TypeDescriptor(getClass().getField("collectionMapTarget"));
+
assertFalse(conversionService.canConvert(sourceType, targetType));
try {
conversionService.convert(map, sourceType, targetType);
@@ -138,6 +154,7 @@ public class MapToMapConverterTests {
catch (ConverterNotFoundException ex) {
// expected
}
+
conversionService.addConverter(new CollectionToCollectionConverter(conversionService));
conversionService.addConverterFactory(new StringToNumberConverterFactory());
assertTrue(conversionService.canConvert(sourceType, targetType));
@@ -153,6 +170,7 @@ public class MapToMapConverterTests {
Map<String, List<String>> map = new HashMap<String, List<String>>();
map.put("1", Arrays.asList("9", "12"));
map.put("2", Arrays.asList("37", "23"));
+
assertTrue(conversionService.canConvert(Map.class, Map.class));
assertSame(map, conversionService.convert(map, Map.class));
}
@@ -164,6 +182,7 @@ public class MapToMapConverterTests {
map.put("2", Arrays.asList("37", "23"));
conversionService.addConverter(new CollectionToCollectionConverter(conversionService));
conversionService.addConverter(new CollectionToObjectConverter(conversionService));
+
assertTrue(conversionService.canConvert(Map.class, Map.class));
assertSame(map, conversionService.convert(map, Map.class));
}
@@ -173,6 +192,7 @@ public class MapToMapConverterTests {
Map<String, String> map = new HashMap<String, String>();
TypeDescriptor sourceType = TypeDescriptor.forObject(map);
TypeDescriptor targetType = new TypeDescriptor(getClass().getField("emptyMapTarget"));
+
assertTrue(conversionService.canConvert(sourceType, targetType));
assertSame(map, conversionService.convert(map, sourceType, targetType));
}
@@ -180,6 +200,7 @@ public class MapToMapConverterTests {
@Test
public void emptyMapNoTargetGenericInfo() throws Exception {
Map<String, String> map = new HashMap<String, String>();
+
assertTrue(conversionService.canConvert(Map.class, Map.class));
assertSame(map, conversionService.convert(map, Map.class));
}
@@ -189,6 +210,7 @@ public class MapToMapConverterTests {
Map<String, String> map = new HashMap<String, String>();
TypeDescriptor sourceType = TypeDescriptor.forObject(map);
TypeDescriptor targetType = new TypeDescriptor(getClass().getField("emptyMapDifferentTarget"));
+
assertTrue(conversionService.canConvert(sourceType, targetType));
@SuppressWarnings("unchecked")
LinkedHashMap<String, String> result = (LinkedHashMap<String, String>) conversionService.convert(map, sourceType, targetType);
@@ -205,6 +227,7 @@ public class MapToMapConverterTests {
TypeDescriptor.valueOf(String.class), TypeDescriptor.valueOf(Integer.class));
TypeDescriptor targetType = TypeDescriptor.map(NoDefaultConstructorMap.class,
TypeDescriptor.valueOf(String.class), TypeDescriptor.valueOf(Integer.class));
+
assertTrue(conversionService.canConvert(sourceType, targetType));
@SuppressWarnings("unchecked")
Map<String, Integer> result = (Map<String, Integer>) conversionService.convert(map, sourceType, targetType);
@@ -220,6 +243,7 @@ public class MapToMapConverterTests {
source.put("a", Arrays.asList(1, 2, 3));
source.put("b", Arrays.asList(4, 5, 6));
TypeDescriptor targetType = new TypeDescriptor(getClass().getField("multiValueMapTarget"));
+
MultiValueMap<String, String> converted = (MultiValueMap<String, String>) conversionService.convert(source, targetType);
assertThat(converted.size(), equalTo(2));
assertThat(converted.get("a"), equalTo(Arrays.asList("1", "2", "3")));
@@ -234,6 +258,7 @@ public class MapToMapConverterTests {
source.put("a", 1);
source.put("b", 2);
TypeDescriptor targetType = new TypeDescriptor(getClass().getField("multiValueMapTarget"));
+
MultiValueMap<String, String> converted = (MultiValueMap<String, String>) conversionService.convert(source, targetType);
assertThat(converted.size(), equalTo(2));
assertThat(converted.get("a"), equalTo(Arrays.asList("1")));
@@ -249,23 +274,12 @@ public class MapToMapConverterTests {
EnumMap<MyEnum, Integer> result = new EnumMap<MyEnum, Integer>(MyEnum.class);
result.put(MyEnum.A, 1);
result.put(MyEnum.C, 2);
- assertEquals(result,
- conversionService.convert(source, TypeDescriptor.forObject(source), new TypeDescriptor(getClass().getField("enumMap"))));
- }
-
-
- @SuppressWarnings("serial")
- public static class NoDefaultConstructorMap<K, V> extends HashMap<K, V> {
- public NoDefaultConstructorMap(Map<? extends K, ? extends V> map) {
- super(map);
- }
+ assertEquals(result, conversionService.convert(source,
+ TypeDescriptor.forObject(source), new TypeDescriptor(getClass().getField("enumMap"))));
}
- public static enum MyEnum {A, B, C}
-
-
public Map<Integer, Integer> scalarMapTarget;
public Map<Integer, List<Integer>> collectionMapTarget;
@@ -283,4 +297,16 @@ public class MapToMapConverterTests {
public EnumMap<MyEnum, Integer> enumMap;
+
+ @SuppressWarnings("serial")
+ public static class NoDefaultConstructorMap<K, V> extends HashMap<K, V> {
+
+ public NoDefaultConstructorMap(Map<? extends K, ? extends V> map) {
+ super(map);
+ }
+ }
+
+
+ public enum MyEnum {A, B, C}
+
}
diff --git a/spring-core/src/test/java/org/springframework/core/convert/support/StreamConverterTests.java b/spring-core/src/test/java/org/springframework/core/convert/support/StreamConverterTests.java
index 6b09204e..2da31bf1 100644
--- a/spring-core/src/test/java/org/springframework/core/convert/support/StreamConverterTests.java
+++ b/spring-core/src/test/java/org/springframework/core/convert/support/StreamConverterTests.java
@@ -49,6 +49,7 @@ public class StreamConverterTests {
private final StreamConverter streamConverter = new StreamConverter(this.conversionService);
+
@Before
public void setup() {
this.conversionService.addConverter(new CollectionToCollectionConverter(this.conversionService));
@@ -57,13 +58,15 @@ public class StreamConverterTests {
this.conversionService.addConverter(this.streamConverter);
}
+
@Test
public void convertFromStreamToList() throws NoSuchFieldException {
this.conversionService.addConverter(Number.class, String.class, new ObjectToStringConverter());
Stream<Integer> stream = Arrays.asList(1, 2, 3).stream();
TypeDescriptor listOfStrings = new TypeDescriptor(Types.class.getField("listOfStrings")); ;
Object result = this.conversionService.convert(stream, listOfStrings);
- assertNotNull("converted object must not be null", result);
+
+ assertNotNull("Converted object must not be null", result);
assertTrue("Converted object must be a list", result instanceof List);
@SuppressWarnings("unchecked")
List<String> content = (List<String>) result;
@@ -79,7 +82,8 @@ public class StreamConverterTests {
Stream<Integer> stream = Arrays.asList(1, 2, 3).stream();
TypeDescriptor arrayOfLongs = new TypeDescriptor(Types.class.getField("arrayOfLongs")); ;
Object result = this.conversionService.convert(stream, arrayOfLongs);
- assertNotNull("converted object must not be null", result);
+
+ assertNotNull("Converted object must not be null", result);
assertTrue("Converted object must be an array", result.getClass().isArray());
Long[] content = (Long[]) result;
assertEquals(Long.valueOf(1L), content[0]);
@@ -93,7 +97,8 @@ public class StreamConverterTests {
Stream<Integer> stream = Arrays.asList(1, 2, 3).stream();
TypeDescriptor listOfStrings = new TypeDescriptor(Types.class.getField("rawList")); ;
Object result = this.conversionService.convert(stream, listOfStrings);
- assertNotNull("converted object must not be null", result);
+
+ assertNotNull("Converted object must not be null", result);
assertTrue("Converted object must be a list", result instanceof List);
@SuppressWarnings("unchecked")
List<Object> content = (List<Object>) result;
@@ -120,7 +125,8 @@ public class StreamConverterTests {
List<String> stream = Arrays.asList("1", "2", "3");
TypeDescriptor streamOfInteger = new TypeDescriptor(Types.class.getField("streamOfIntegers")); ;
Object result = this.conversionService.convert(stream, streamOfInteger);
- assertNotNull("converted object must not be null", result);
+
+ assertNotNull("Converted object must not be null", result);
assertTrue("Converted object must be a stream", result instanceof Stream);
@SuppressWarnings("unchecked")
Stream<Integer> content = (Stream<Integer>) result;
@@ -139,7 +145,8 @@ public class StreamConverterTests {
});
TypeDescriptor streamOfBoolean = new TypeDescriptor(Types.class.getField("streamOfBooleans")); ;
Object result = this.conversionService.convert(stream, streamOfBoolean);
- assertNotNull("converted object must not be null", result);
+
+ assertNotNull("Converted object must not be null", result);
assertTrue("Converted object must be a stream", result instanceof Stream);
@SuppressWarnings("unchecked")
Stream<Boolean> content = (Stream<Boolean>) result;
@@ -152,7 +159,8 @@ public class StreamConverterTests {
List<String> stream = Arrays.asList("1", "2", "3");
TypeDescriptor streamOfInteger = new TypeDescriptor(Types.class.getField("rawStream")); ;
Object result = this.conversionService.convert(stream, streamOfInteger);
- assertNotNull("converted object must not be null", result);
+
+ assertNotNull("Converted object must not be null", result);
assertTrue("Converted object must be a stream", result instanceof Stream);
@SuppressWarnings("unchecked")
Stream<Object> content = (Stream<Object>) result;
@@ -175,6 +183,7 @@ public class StreamConverterTests {
new TypeDescriptor(Types.class.getField("arrayOfLongs")));
}
+
@SuppressWarnings({ "rawtypes" })
static class Types {
diff --git a/spring-core/src/test/java/org/springframework/core/env/DummyEnvironment.java b/spring-core/src/test/java/org/springframework/core/env/DummyEnvironment.java
index bcb3d225..756da6a9 100644
--- a/spring-core/src/test/java/org/springframework/core/env/DummyEnvironment.java
+++ b/spring-core/src/test/java/org/springframework/core/env/DummyEnvironment.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2013 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -44,6 +44,7 @@ public class DummyEnvironment implements Environment {
}
@Override
+ @Deprecated
public <T> Class<T> getPropertyAsClass(String key, Class<T> targetType) {
return null;
}
@@ -54,8 +55,7 @@ public class DummyEnvironment implements Environment {
}
@Override
- public <T> T getRequiredProperty(String key, Class<T> targetType)
- throws IllegalStateException {
+ public <T> T getRequiredProperty(String key, Class<T> targetType) throws IllegalStateException {
return null;
}
@@ -65,8 +65,7 @@ public class DummyEnvironment implements Environment {
}
@Override
- public String resolveRequiredPlaceholders(String text)
- throws IllegalArgumentException {
+ public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
return null;
}
diff --git a/spring-core/src/test/java/org/springframework/core/env/PropertySourceTests.java b/spring-core/src/test/java/org/springframework/core/env/PropertySourceTests.java
index 28a51d05..fda1f06d 100644
--- a/spring-core/src/test/java/org/springframework/core/env/PropertySourceTests.java
+++ b/spring-core/src/test/java/org/springframework/core/env/PropertySourceTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -30,13 +30,15 @@ import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
/**
- * Unit tests for {@link AbstractPropertySource} implementations.
+ * Unit tests for {@link PropertySource} implementations.
*
* @author Chris Beams
* @since 3.1
*/
public class PropertySourceTests {
- @Test @SuppressWarnings("serial")
+
+ @Test
+ @SuppressWarnings("serial")
public void equals() {
Map<String, Object> map1 = new HashMap<String, Object>() {{ put("a", "b"); }};
Map<String, Object> map2 = new HashMap<String, Object>() {{ put("c", "d"); }};
@@ -59,14 +61,15 @@ public class PropertySourceTests {
assertThat(new MapPropertySource("x", map1).equals(new PropertiesPropertySource("y", props2)), is(false));
}
- @Test @SuppressWarnings("serial")
+ @Test
+ @SuppressWarnings("serial")
public void collectionsOperations() {
Map<String, Object> map1 = new HashMap<String, Object>() {{ put("a", "b"); }};
Map<String, Object> map2 = new HashMap<String, Object>() {{ put("c", "d"); }};
PropertySource<?> ps1 = new MapPropertySource("ps1", map1);
ps1.getSource();
- List<PropertySource<?>> propertySources = new ArrayList<PropertySource<?>>();
+ List<PropertySource<?>> propertySources = new ArrayList<>();
assertThat(propertySources.add(ps1), equalTo(true));
assertThat(propertySources.contains(ps1), is(true));
assertThat(propertySources.contains(PropertySource.named("ps1")), is(true));
@@ -110,10 +113,11 @@ public class PropertySourceTests {
ps.toString(),
equalTo(String.format("%s [name='%s']",
ps.getClass().getSimpleName(),
- name,
- map.size())));
- } finally {
+ name)));
+ }
+ finally {
logger.setLevel(original);
}
}
+
}
diff --git a/spring-core/src/test/java/org/springframework/core/env/PropertySourcesPropertyResolverTests.java b/spring-core/src/test/java/org/springframework/core/env/PropertySourcesPropertyResolverTests.java
index 84f6fce0..529bcd41 100644
--- a/spring-core/src/test/java/org/springframework/core/env/PropertySourcesPropertyResolverTests.java
+++ b/spring-core/src/test/java/org/springframework/core/env/PropertySourcesPropertyResolverTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2013 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -24,6 +24,7 @@ import org.junit.Before;
import org.junit.Test;
import org.springframework.core.convert.ConversionException;
+import org.springframework.core.convert.ConverterNotFoundException;
import org.springframework.mock.env.MockPropertySource;
import static org.hamcrest.Matchers.*;
@@ -114,9 +115,9 @@ public class PropertySourcesPropertyResolverTests {
try {
propertyResolver.getProperty("foo", TestType.class);
- fail("Expected IllegalArgumentException due to non-convertible types");
+ fail("Expected ConverterNotFoundException due to non-convertible types");
}
- catch (IllegalArgumentException ex) {
+ catch (ConverterNotFoundException ex) {
// expected
}
}
@@ -257,6 +258,7 @@ public class PropertySourcesPropertyResolverTests {
}
@Test
+ @SuppressWarnings("deprecation")
public void getPropertyAsClass() throws ClassNotFoundException, LinkageError {
MutablePropertySources propertySources = new MutablePropertySources();
propertySources.addFirst(new MockPropertySource().withProperty("some.class", SpecificType.class.getName()));
@@ -265,6 +267,7 @@ public class PropertySourcesPropertyResolverTests {
}
@Test
+ @SuppressWarnings("deprecation")
public void getPropertyAsClass_withInterfaceAsTarget() throws ClassNotFoundException, LinkageError {
MutablePropertySources propertySources = new MutablePropertySources();
propertySources.addFirst(new MockPropertySource().withProperty("some.class", SomeType.class.getName()));
@@ -272,7 +275,8 @@ public class PropertySourcesPropertyResolverTests {
assertTrue(resolver.getPropertyAsClass("some.class", SomeType.class).equals(SomeType.class));
}
- @Test(expected=ConversionException.class)
+ @Test(expected = ConversionException.class)
+ @SuppressWarnings("deprecation")
public void getPropertyAsClass_withMismatchedTypeForValue() {
MutablePropertySources propertySources = new MutablePropertySources();
propertySources.addFirst(new MockPropertySource().withProperty("some.class", "java.lang.String"));
@@ -280,7 +284,8 @@ public class PropertySourcesPropertyResolverTests {
resolver.getPropertyAsClass("some.class", SomeType.class);
}
- @Test(expected=ConversionException.class)
+ @Test(expected = ConversionException.class)
+ @SuppressWarnings("deprecation")
public void getPropertyAsClass_withNonExistentClassForValue() {
MutablePropertySources propertySources = new MutablePropertySources();
propertySources.addFirst(new MockPropertySource().withProperty("some.class", "some.bogus.Class"));
@@ -289,6 +294,7 @@ public class PropertySourcesPropertyResolverTests {
}
@Test
+ @SuppressWarnings("deprecation")
public void getPropertyAsClass_withObjectForValue() {
MutablePropertySources propertySources = new MutablePropertySources();
propertySources.addFirst(new MockPropertySource().withProperty("some.class", new SpecificType()));
@@ -296,7 +302,8 @@ public class PropertySourcesPropertyResolverTests {
assertTrue(resolver.getPropertyAsClass("some.class", SomeType.class).equals(SpecificType.class));
}
- @Test(expected=ConversionException.class)
+ @Test(expected = ConversionException.class)
+ @SuppressWarnings("deprecation")
public void getPropertyAsClass_withMismatchedObjectForValue() {
MutablePropertySources propertySources = new MutablePropertySources();
propertySources.addFirst(new MockPropertySource().withProperty("some.class", new Integer(42)));
@@ -305,6 +312,7 @@ public class PropertySourcesPropertyResolverTests {
}
@Test
+ @SuppressWarnings("deprecation")
public void getPropertyAsClass_withRealClassForValue() {
MutablePropertySources propertySources = new MutablePropertySources();
propertySources.addFirst(new MockPropertySource().withProperty("some.class", SpecificType.class));
@@ -312,7 +320,8 @@ public class PropertySourcesPropertyResolverTests {
assertTrue(resolver.getPropertyAsClass("some.class", SomeType.class).equals(SpecificType.class));
}
- @Test(expected=ConversionException.class)
+ @Test(expected = ConversionException.class)
+ @SuppressWarnings("deprecation")
public void getPropertyAsClass_withMismatchedRealClassForValue() {
MutablePropertySources propertySources = new MutablePropertySources();
propertySources.addFirst(new MockPropertySource().withProperty("some.class", Integer.class));
diff --git a/spring-core/src/test/java/org/springframework/core/env/SystemEnvironmentPropertySourceTests.java b/spring-core/src/test/java/org/springframework/core/env/SystemEnvironmentPropertySourceTests.java
index 8926161a..935862b0 100644
--- a/spring-core/src/test/java/org/springframework/core/env/SystemEnvironmentPropertySourceTests.java
+++ b/spring-core/src/test/java/org/springframework/core/env/SystemEnvironmentPropertySourceTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2014 the original author or authors.
+ * Copyright 2002-2015 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.
@@ -93,16 +93,59 @@ public class SystemEnvironmentPropertySourceTests {
@Test
public void withUppercase() {
envMap.put("A_KEY", "a_value");
+ envMap.put("A_LONG_KEY", "a_long_value");
+ envMap.put("A_DOT.KEY", "a_dot_value");
+ envMap.put("A_HYPHEN-KEY", "a_hyphen_value");
assertThat(ps.containsProperty("A_KEY"), equalTo(true));
assertThat(ps.containsProperty("A.KEY"), equalTo(true));
+ assertThat(ps.containsProperty("A-KEY"), equalTo(true));
assertThat(ps.containsProperty("a_key"), equalTo(true));
assertThat(ps.containsProperty("a.key"), equalTo(true));
-
- assertThat(ps.getProperty("A_KEY"), equalTo((Object)"a_value"));
- assertThat(ps.getProperty("A.KEY"), equalTo((Object)"a_value"));
- assertThat(ps.getProperty("a_key"), equalTo((Object)"a_value"));
- assertThat(ps.getProperty("a.key"), equalTo((Object)"a_value"));
+ assertThat(ps.containsProperty("a-key"), equalTo(true));
+ assertThat(ps.containsProperty("A_LONG_KEY"), equalTo(true));
+ assertThat(ps.containsProperty("A.LONG.KEY"), equalTo(true));
+ assertThat(ps.containsProperty("A-LONG-KEY"), equalTo(true));
+ assertThat(ps.containsProperty("A.LONG-KEY"), equalTo(true));
+ assertThat(ps.containsProperty("A-LONG.KEY"), equalTo(true));
+ assertThat(ps.containsProperty("A_long_KEY"), equalTo(true));
+ assertThat(ps.containsProperty("A.long.KEY"), equalTo(true));
+ assertThat(ps.containsProperty("A-long-KEY"), equalTo(true));
+ assertThat(ps.containsProperty("A.long-KEY"), equalTo(true));
+ assertThat(ps.containsProperty("A-long.KEY"), equalTo(true));
+ assertThat(ps.containsProperty("A_DOT.KEY"), equalTo(true));
+ assertThat(ps.containsProperty("A-DOT.KEY"), equalTo(true));
+ assertThat(ps.containsProperty("A_dot.KEY"), equalTo(true));
+ assertThat(ps.containsProperty("A-dot.KEY"), equalTo(true));
+ assertThat(ps.containsProperty("A_HYPHEN-KEY"), equalTo(true));
+ assertThat(ps.containsProperty("A.HYPHEN-KEY"), equalTo(true));
+ assertThat(ps.containsProperty("A_hyphen-KEY"), equalTo(true));
+ assertThat(ps.containsProperty("A.hyphen-KEY"), equalTo(true));
+
+ assertThat(ps.getProperty("A_KEY"), equalTo("a_value"));
+ assertThat(ps.getProperty("A.KEY"), equalTo("a_value"));
+ assertThat(ps.getProperty("A-KEY"), equalTo("a_value"));
+ assertThat(ps.getProperty("a_key"), equalTo("a_value"));
+ assertThat(ps.getProperty("a.key"), equalTo("a_value"));
+ assertThat(ps.getProperty("a-key"), equalTo("a_value"));
+ assertThat(ps.getProperty("A_LONG_KEY"), equalTo("a_long_value"));
+ assertThat(ps.getProperty("A.LONG.KEY"), equalTo("a_long_value"));
+ assertThat(ps.getProperty("A-LONG-KEY"), equalTo("a_long_value"));
+ assertThat(ps.getProperty("A.LONG-KEY"), equalTo("a_long_value"));
+ assertThat(ps.getProperty("A-LONG.KEY"), equalTo("a_long_value"));
+ assertThat(ps.getProperty("A_long_KEY"), equalTo("a_long_value"));
+ assertThat(ps.getProperty("A.long.KEY"), equalTo("a_long_value"));
+ assertThat(ps.getProperty("A-long-KEY"), equalTo("a_long_value"));
+ assertThat(ps.getProperty("A.long-KEY"), equalTo("a_long_value"));
+ assertThat(ps.getProperty("A-long.KEY"), equalTo("a_long_value"));
+ assertThat(ps.getProperty("A_DOT.KEY"), equalTo("a_dot_value"));
+ assertThat(ps.getProperty("A-DOT.KEY"), equalTo("a_dot_value"));
+ assertThat(ps.getProperty("A_dot.KEY"), equalTo("a_dot_value"));
+ assertThat(ps.getProperty("A-dot.KEY"), equalTo("a_dot_value"));
+ assertThat(ps.getProperty("A_HYPHEN-KEY"), equalTo("a_hyphen_value"));
+ assertThat(ps.getProperty("A.HYPHEN-KEY"), equalTo("a_hyphen_value"));
+ assertThat(ps.getProperty("A_hyphen-KEY"), equalTo("a_hyphen_value"));
+ assertThat(ps.getProperty("A.hyphen-KEY"), equalTo("a_hyphen_value"));
}
@Test
diff --git a/spring-core/src/test/java/org/springframework/tests/BuildTests.java b/spring-core/src/test/java/org/springframework/core/io/support/DummyPackagePrivateFactory.java
index ee704806..4c83bfab 100644
--- a/spring-core/src/test/java/org/springframework/tests/BuildTests.java
+++ b/spring-core/src/test/java/org/springframework/core/io/support/DummyPackagePrivateFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2013 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -14,23 +14,13 @@
* limitations under the License.
*/
-package org.springframework.tests;
-
-import org.junit.Test;
-
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
+package org.springframework.core.io.support;
/**
- * General build related tests. Part of spring-core to ensure that they run early in the
- * build process.
- */
-public class BuildTests {
+ * Used by {@link SpringFactoriesLoaderTests}
- @Test
- public void javaVersion() throws Exception {
- Assume.group(TestGroup.CI);
- assertThat("Java Version", JavaVersion.runningVersion(), equalTo(JavaVersion.JAVA_18));
- }
+ * @author Phillip Webb
+ */
+class DummyPackagePrivateFactory {
}
diff --git a/spring-core/src/test/java/org/springframework/core/io/support/ResourceRegionTests.java b/spring-core/src/test/java/org/springframework/core/io/support/ResourceRegionTests.java
new file mode 100644
index 00000000..8ee0fef2
--- /dev/null
+++ b/spring-core/src/test/java/org/springframework/core/io/support/ResourceRegionTests.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2002-2016 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.io.support;
+
+import org.junit.Test;
+
+import org.springframework.core.io.Resource;
+
+import static org.mockito.Mockito.*;
+
+/**
+ * Unit tests for the {@link ResourceRegion} class.
+ *
+ * @author Brian Clozel
+ */
+public class ResourceRegionTests {
+
+ @Test(expected = IllegalArgumentException.class)
+ public void shouldThrowExceptionWithNullResource() {
+ new ResourceRegion(null, 0, 1);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void shouldThrowExceptionForNegativePosition() {
+ new ResourceRegion(mock(Resource.class), -1, 1);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void shouldThrowExceptionForNegativeCount() {
+ new ResourceRegion(mock(Resource.class), 0, -1);
+ }
+
+}
diff --git a/spring-core/src/test/java/org/springframework/core/io/support/SpringFactoriesLoaderTests.java b/spring-core/src/test/java/org/springframework/core/io/support/SpringFactoriesLoaderTests.java
new file mode 100644
index 00000000..4de87d2c
--- /dev/null
+++ b/spring-core/src/test/java/org/springframework/core/io/support/SpringFactoriesLoaderTests.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2002-2016 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.io.support;
+
+import java.lang.reflect.Modifier;
+import java.util.List;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Tests for {@link SpringFactoriesLoader}.
+ *
+ * @author Arjen Poutsma
+ * @author Phillip Webb
+ */
+public class SpringFactoriesLoaderTests {
+
+ @Test
+ public void loadFactoriesInCorrectOrder() {
+ List<DummyFactory> factories = SpringFactoriesLoader
+ .loadFactories(DummyFactory.class, null);
+ assertEquals(2, factories.size());
+ assertTrue(factories.get(0) instanceof MyDummyFactory1);
+ assertTrue(factories.get(1) instanceof MyDummyFactory2);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void loadInvalid() {
+ SpringFactoriesLoader.loadFactories(String.class, null);
+ }
+
+ @Test
+ public void loadPackagePrivateFactory() throws Exception {
+ List<DummyPackagePrivateFactory> factories = SpringFactoriesLoader
+ .loadFactories(DummyPackagePrivateFactory.class, null);
+ assertEquals(1, factories.size());
+ assertTrue((factories.get(0).getClass().getModifiers() & Modifier.PUBLIC) == 0);
+ }
+
+}
diff --git a/spring-core/src/test/java/org/springframework/core/type/AnnotationMetadataTests.java b/spring-core/src/test/java/org/springframework/core/type/AnnotationMetadataTests.java
index 5e4083e0..2f377fc0 100644
--- a/spring-core/src/test/java/org/springframework/core/type/AnnotationMetadataTests.java
+++ b/spring-core/src/test/java/org/springframework/core/type/AnnotationMetadataTests.java
@@ -30,6 +30,7 @@ import java.util.Set;
import org.junit.Test;
+import org.springframework.core.annotation.AliasFor;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
@@ -291,6 +292,7 @@ public class AnnotationMetadataTests {
Set<MethodMetadata> methods = metadata.getAnnotatedMethods(DirectAnnotation.class.getName());
MethodMetadata method = methods.iterator().next();
assertEquals("direct", method.getAnnotationAttributes(DirectAnnotation.class.getName()).get("value"));
+ assertEquals("direct", method.getAnnotationAttributes(DirectAnnotation.class.getName()).get("myValue"));
List<Object> allMeta = method.getAllAnnotationAttributes(DirectAnnotation.class.getName()).get("value");
assertThat(new HashSet<Object>(allMeta), is(equalTo(new HashSet<Object>(Arrays.asList("direct", "meta")))));
allMeta = method.getAllAnnotationAttributes(DirectAnnotation.class.getName()).get("additional");
@@ -416,7 +418,11 @@ public class AnnotationMetadataTests {
@Retention(RetentionPolicy.RUNTIME)
public @interface DirectAnnotation {
- String value();
+ @AliasFor("myValue")
+ String value() default "";
+
+ @AliasFor("value")
+ String myValue() default "";
String additional() default "direct";
}
@@ -449,7 +455,7 @@ public class AnnotationMetadataTests {
}
// SPR-10914
- public static enum SubclassEnum {
+ public enum SubclassEnum {
FOO {
/* Do not delete! This subclassing is intentional. */
},
@@ -489,14 +495,14 @@ public class AnnotationMetadataTests {
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Component
- public static @interface TestConfiguration {
+ public @interface TestConfiguration {
String value() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
- public static @interface TestComponentScan {
+ public @interface TestComponentScan {
String[] value() default {};
@@ -509,7 +515,7 @@ public class AnnotationMetadataTests {
@TestComponentScan(basePackages = "bogus")
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
- public static @interface ComposedConfigurationWithAttributeOverrides {
+ public @interface ComposedConfigurationWithAttributeOverrides {
String[] basePackages() default {};
}
@@ -520,19 +526,19 @@ public class AnnotationMetadataTests {
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
- public static @interface NamedAnnotation1 {
+ public @interface NamedAnnotation1 {
String name() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
- public static @interface NamedAnnotation2 {
+ public @interface NamedAnnotation2 {
String name() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
- public static @interface NamedAnnotation3 {
+ public @interface NamedAnnotation3 {
String name() default "";
}
@@ -547,7 +553,7 @@ public class AnnotationMetadataTests {
@NamedAnnotation3(name = "name 3")
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
- public static @interface NamedComposedAnnotation {
+ public @interface NamedComposedAnnotation {
}
@NamedComposedAnnotation
diff --git a/spring-core/src/test/java/org/springframework/core/type/classreading/ClassMetadataReadingVisitorMemberClassTests.java b/spring-core/src/test/java/org/springframework/core/type/classreading/ClassMetadataReadingVisitorMemberClassTests.java
index cc4ca072..5553f170 100644
--- a/spring-core/src/test/java/org/springframework/core/type/classreading/ClassMetadataReadingVisitorMemberClassTests.java
+++ b/spring-core/src/test/java/org/springframework/core/type/classreading/ClassMetadataReadingVisitorMemberClassTests.java
@@ -35,7 +35,8 @@ public class ClassMetadataReadingVisitorMemberClassTests
MetadataReader reader =
new SimpleMetadataReaderFactory().getMetadataReader(clazz.getName());
return reader.getAnnotationMetadata();
- } catch (IOException ex) {
+ }
+ catch (IOException ex) {
throw new IllegalStateException(ex);
}
}
diff --git a/spring-core/src/test/java/org/springframework/tests/Assume.java b/spring-core/src/test/java/org/springframework/tests/Assume.java
index e7923851..cd26d368 100644
--- a/spring-core/src/test/java/org/springframework/tests/Assume.java
+++ b/spring-core/src/test/java/org/springframework/tests/Assume.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2015 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -21,7 +21,6 @@ import java.lang.reflect.Method;
import java.util.Set;
import org.apache.commons.logging.Log;
-
import org.junit.AssumptionViolatedException;
import org.springframework.util.ClassUtils;
@@ -33,38 +32,8 @@ import static org.junit.Assume.*;
* conditions hold {@code true}. If the assumption fails, it means the test should be
* skipped.
*
- * <p>For example, if a set of tests require at least JDK 1.7 it can use
- * {@code Assume#atLeast(JavaVersion.JAVA_17)} as shown below:
- *
- * <pre class="code">
- * public void MyTests {
- *
- * &#064;BeforeClass
- * public static void assumptions() {
- * Assume.atLeast(JavaVersion.JAVA_17);
- * }
- *
- * // ... all the test methods that require at least JDK 1.7
- * }
- * </pre>
- *
- * If only a single test requires at least JDK 1.7 it can use the
- * {@code Assume#atLeast(JavaVersion.JAVA_17)} as shown below:
- *
- * <pre class="code">
- * public void MyTests {
- *
- * &#064;Test
- * public void requiresJdk17 {
- * Assume.atLeast(JavaVersion.JAVA_17);
- * // ... perform the actual test
- * }
- * }
- * </pre>
- *
- * In addition to assumptions based on the JDK version, tests can be categorized into
- * {@link TestGroup}s. Active groups are enabled using the 'testGroups' system property,
- * usually activated from the gradle command line:
+ * Tests can be categorized into {@link TestGroup}s. Active groups are enabled using
+ * the 'testGroups' system property, usually activated from the gradle command line:
* <pre>
* gradle test -PtestGroups="performance"
* </pre>
@@ -76,7 +45,6 @@ import static org.junit.Assume.*;
* @author Phillip Webb
* @author Sam Brannen
* @since 3.2
- * @see #atLeast(JavaVersion)
* @see #group(TestGroup)
* @see #group(TestGroup, Executable)
*/
@@ -86,26 +54,13 @@ public abstract class Assume {
/**
- * Assume that a minimum {@link JavaVersion} is running.
- * @param version the minimum version for the test to run
- * @throws AssumptionViolatedException if the assumption fails
- */
- public static void atLeast(JavaVersion version) {
- if (!JavaVersion.runningVersion().isAtLeast(version)) {
- throw new AssumptionViolatedException("Requires JDK " + version + " but running "
- + JavaVersion.runningVersion());
- }
- }
-
- /**
* Assume that a particular {@link TestGroup} has been specified.
* @param group the group that must be specified
* @throws AssumptionViolatedException if the assumption fails
*/
public static void group(TestGroup group) {
if (!GROUPS.contains(group)) {
- throw new AssumptionViolatedException("Requires unspecified group " + group
- + " from " + GROUPS);
+ throw new AssumptionViolatedException("Requires unspecified group " + group + " from " + GROUPS);
}
}
@@ -154,11 +109,12 @@ public abstract class Assume {
}
}
+
/**
* @since 4.2
*/
- @FunctionalInterface
- public static interface Executable {
+ public interface Executable {
+
void execute() throws Exception;
}
diff --git a/spring-core/src/test/java/org/springframework/tests/JavaVersion.java b/spring-core/src/test/java/org/springframework/tests/JavaVersion.java
deleted file mode 100644
index ac4e78ad..00000000
--- a/spring-core/src/test/java/org/springframework/tests/JavaVersion.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright 2002-2015 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.tests;
-
-/**
- * Enumeration of known JDK versions.
- *
- * @author Phillip Webb
- * @see #runningVersion()
- */
-public enum JavaVersion {
-
- /**
- * Java 1.6
- */
- JAVA_16("1.6", 16),
-
- /**
- * Java 1.7
- */
- JAVA_17("1.7", 17),
-
- /**
- * Java 1.8
- */
- JAVA_18("1.8", 18),
-
- /**
- * Java 1.9
- */
- JAVA_19("1.9", 19);
-
-
- private static final JavaVersion runningVersion = findRunningVersion();
-
- private static JavaVersion findRunningVersion() {
- String version = System.getProperty("java.version");
- for (JavaVersion candidate : values()) {
- if (version.startsWith(candidate.version)) {
- return candidate;
- }
- }
- return JavaVersion.JAVA_16;
- }
-
-
- private String version;
-
- private int value;
-
-
- private JavaVersion(String version, int value) {
- this.version = version;
- this.value = value;
- }
-
-
- @Override
- public String toString() {
- return version;
- }
-
- /**
- * Determines if the specified version is the same as or greater than this version.
- * @param version the version to check
- * @return {@code true} if the specified version is at least this version
- */
- public boolean isAtLeast(JavaVersion version) {
- return (this.value >= version.value);
- }
-
- /**
- * Returns the current running JDK version. If the current version cannot be
- * determined {@link #JAVA_16} will be returned.
- * @return the JDK version
- */
- public static JavaVersion runningVersion() {
- return runningVersion;
- }
-
-}
diff --git a/spring-core/src/test/java/org/springframework/tests/JavaVersionTests.java b/spring-core/src/test/java/org/springframework/tests/JavaVersionTests.java
deleted file mode 100644
index 05c341fb..00000000
--- a/spring-core/src/test/java/org/springframework/tests/JavaVersionTests.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2002-2015 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.tests;
-
-import org.junit.Test;
-
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-
-/**
- * Tests for {@link JavaVersion}.
- *
- * @author Phillip Webb
- */
-public class JavaVersionTests {
-
- @Test
- public void runningVersion() {
- assertNotNull(JavaVersion.runningVersion());
- assertThat(System.getProperty("java.version"), startsWith(JavaVersion.runningVersion().toString()));
- }
-
- @Test
- public void isAtLeast() throws Exception {
- assertTrue(JavaVersion.JAVA_16.isAtLeast(JavaVersion.JAVA_16));
- assertFalse(JavaVersion.JAVA_16.isAtLeast(JavaVersion.JAVA_17));
- }
-
-}
diff --git a/spring-core/src/test/java/org/springframework/tests/TestGroup.java b/spring-core/src/test/java/org/springframework/tests/TestGroup.java
index f7b8525b..9a10ce12 100644
--- a/spring-core/src/test/java/org/springframework/tests/TestGroup.java
+++ b/spring-core/src/test/java/org/springframework/tests/TestGroup.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2015 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -58,14 +58,7 @@ public enum TestGroup {
/**
* Tests that should only be run on the continuous integration server.
*/
- CI,
-
- /**
- * Tests that require custom compilation beyond that of the standard JDK. This helps to
- * allow running tests that will otherwise fail when using JDK > 1.8 b88. See
- * <a href="https://jira.spring.io/browse/SPR-10558">SPR-10558</a>
- */
- CUSTOM_COMPILATION;
+ CI;
/**
diff --git a/spring-core/src/test/java/org/springframework/tests/TestGroupTests.java b/spring-core/src/test/java/org/springframework/tests/TestGroupTests.java
index f756bb31..291fba3a 100644
--- a/spring-core/src/test/java/org/springframework/tests/TestGroupTests.java
+++ b/spring-core/src/test/java/org/springframework/tests/TestGroupTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2013 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -38,6 +38,7 @@ public class TestGroupTests {
@Rule
public ExpectedException thrown = ExpectedException.none();
+
@Test
public void parseNull() throws Exception {
assertThat(TestGroup.parse(null), equalTo(Collections.<TestGroup> emptySet()));
@@ -65,7 +66,7 @@ public class TestGroupTests {
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("Unable to find test group 'missing' when parsing " +
"testGroups value: 'performance, missing'. Available groups include: " +
- "[LONG_RUNNING,PERFORMANCE,JMXMP,CI,CUSTOM_COMPILATION]");
+ "[LONG_RUNNING,PERFORMANCE,JMXMP,CI]");
TestGroup.parse("performance, missing");
}
@@ -77,9 +78,8 @@ public class TestGroupTests {
@Test
public void parseAllExcept() throws Exception {
Set<TestGroup> expected = new HashSet<TestGroup>(EnumSet.allOf(TestGroup.class));
- expected.remove(TestGroup.CUSTOM_COMPILATION);
expected.remove(TestGroup.PERFORMANCE);
- assertThat(TestGroup.parse("all-custom_compilation,performance"), equalTo(expected));
+ assertThat(TestGroup.parse("all-performance"), equalTo(expected));
}
}
diff --git a/spring-core/src/test/java/org/springframework/util/AntPathMatcherTests.java b/spring-core/src/test/java/org/springframework/util/AntPathMatcherTests.java
index 29a2486a..d810c330 100644
--- a/spring-core/src/test/java/org/springframework/util/AntPathMatcherTests.java
+++ b/spring-core/src/test/java/org/springframework/util/AntPathMatcherTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2015 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -53,6 +53,7 @@ public class AntPathMatcherTests {
// test exact matching
assertTrue(pathMatcher.match("test", "test"));
assertTrue(pathMatcher.match("/test", "/test"));
+ assertTrue(pathMatcher.match("http://example.org", "http://example.org")); // SPR-14141
assertFalse(pathMatcher.match("/test.jpg", "test.jpg"));
assertFalse(pathMatcher.match("test", "/test"));
assertFalse(pathMatcher.match("/test", "test"));
@@ -128,11 +129,21 @@ public class AntPathMatcherTests {
assertFalse(pathMatcher.match("/x/x/**/bla", "/x/x/x/"));
+ assertTrue(pathMatcher.match("/foo/bar/**", "/foo/bar")) ;
+
assertTrue(pathMatcher.match("", ""));
assertTrue(pathMatcher.match("/{bla}.*", "/testing.html"));
}
+ // SPR-14247
+ @Test
+ public void matchWithTrimTokensEnabled() throws Exception {
+ pathMatcher.setTrimTokens(true);
+
+ assertTrue(pathMatcher.match("/foo/bar", "/foo /bar"));
+ }
+
@Test
public void withMatchStart() {
// test exact matching
@@ -418,8 +429,8 @@ public class AntPathMatcherTests {
assertEquals("/*.html", pathMatcher.combine("/**", "/*.html"));
assertEquals("/*.html", pathMatcher.combine("/*", "/*.html"));
assertEquals("/*.html", pathMatcher.combine("/*.*", "/*.html"));
- assertEquals("/{foo}/bar", pathMatcher.combine("/{foo}", "/bar")); // SPR-8858
- assertEquals("/user/user", pathMatcher.combine("/user", "/user")); // SPR-7970
+ assertEquals("/{foo}/bar", pathMatcher.combine("/{foo}", "/bar")); // SPR-8858
+ assertEquals("/user/user", pathMatcher.combine("/user", "/user")); // SPR-7970
assertEquals("/{foo:.*[^0-9].*}/edit/", pathMatcher.combine("/{foo:.*[^0-9].*}", "/edit/")); // SPR-10062
assertEquals("/1.0/foo/test", pathMatcher.combine("/1.0", "/foo/test")); // SPR-10554
assertEquals("/hotel", pathMatcher.combine("/", "/hotel")); // SPR-12975
@@ -454,8 +465,8 @@ public class AntPathMatcherTests {
// SPR-10550
assertEquals(-1, comparator.compare("/hotels/{hotel}/bookings/{booking}/cutomers/{customer}", "/**"));
- assertEquals(1, comparator.compare("/**","/hotels/{hotel}/bookings/{booking}/cutomers/{customer}"));
- assertEquals(0, comparator.compare("/**","/**"));
+ assertEquals(1, comparator.compare("/**", "/hotels/{hotel}/bookings/{booking}/cutomers/{customer}"));
+ assertEquals(0, comparator.compare("/**", "/**"));
assertEquals(-1, comparator.compare("/hotels/{hotel}", "/hotels/*"));
assertEquals(1, comparator.compare("/hotels/*", "/hotels/{hotel}"));
@@ -618,13 +629,45 @@ public class AntPathMatcherTests {
assertTrue(pathMatcher.stringMatcherCache.size() > 20);
for (int i = 0; i < 65536; i++) {
- pathMatcher.match("test" + i, "test");
+ pathMatcher.match("test" + i, "test" + i);
}
// Cache keeps being alive due to the explicit cache setting
assertTrue(pathMatcher.stringMatcherCache.size() > 65536);
}
@Test
+ public void preventCreatingStringMatchersIfPathDoesNotStartsWithPatternPrefix() {
+ pathMatcher.setCachePatterns(true);
+ assertEquals(0, pathMatcher.stringMatcherCache.size());
+
+ pathMatcher.match("test?", "test");
+ assertEquals(1, pathMatcher.stringMatcherCache.size());
+
+ pathMatcher.match("test?", "best");
+ pathMatcher.match("test/*", "view/test.jpg");
+ pathMatcher.match("test/**/test.jpg", "view/test.jpg");
+ pathMatcher.match("test/{name}.jpg", "view/test.jpg");
+ assertEquals(1, pathMatcher.stringMatcherCache.size());
+ }
+
+ @Test
+ public void creatingStringMatchersIfPatternPrefixCannotDetermineIfPathMatch() {
+ pathMatcher.setCachePatterns(true);
+ assertEquals(0, pathMatcher.stringMatcherCache.size());
+
+ pathMatcher.match("test", "testian");
+ pathMatcher.match("test?", "testFf");
+ pathMatcher.match("test/*", "test/dir/name.jpg");
+ pathMatcher.match("test/{name}.jpg", "test/lorem.jpg");
+ pathMatcher.match("bla/**/test.jpg", "bla/test.jpg");
+ pathMatcher.match("**/{name}.jpg", "test/lorem.jpg");
+ pathMatcher.match("/**/{name}.jpg", "/test/lorem.jpg");
+ pathMatcher.match("/*/dir/{name}.jpg", "/*/dir/lorem.jpg");
+
+ assertEquals(7, pathMatcher.stringMatcherCache.size());
+ }
+
+ @Test
public void cachePatternsSetToFalse() {
pathMatcher.setCachePatterns(false);
match();
diff --git a/spring-core/src/test/java/org/springframework/util/AutoPopulatingListTests.java b/spring-core/src/test/java/org/springframework/util/AutoPopulatingListTests.java
index ba0980b6..21ce9562 100644
--- a/spring-core/src/test/java/org/springframework/util/AutoPopulatingListTests.java
+++ b/spring-core/src/test/java/org/springframework/util/AutoPopulatingListTests.java
@@ -74,9 +74,9 @@ public class AutoPopulatingListTests {
private void doTestWithElementFactory(AutoPopulatingList<Object> list) {
doTestWithClass(list);
- for(int x = 0; x < list.size(); x++) {
+ for (int x = 0; x < list.size(); x++) {
Object element = list.get(x);
- if(element instanceof TestObject) {
+ if (element instanceof TestObject) {
assertEquals(x, ((TestObject) element).getAge());
}
}
diff --git a/spring-core/src/test/java/org/springframework/util/DigestUtilsTests.java b/spring-core/src/test/java/org/springframework/util/DigestUtilsTests.java
index 6842bfee..5db3ea51 100644
--- a/spring-core/src/test/java/org/springframework/util/DigestUtilsTests.java
+++ b/spring-core/src/test/java/org/springframework/util/DigestUtilsTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2015 the original author or authors.
+ * Copyright 2002-2016 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,6 +16,8 @@
package org.springframework.util;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
import java.io.UnsupportedEncodingException;
import org.junit.Before;
@@ -25,6 +27,7 @@ import static org.junit.Assert.*;
/**
* @author Arjen Poutsma
+ * @author Juergen Hoeller
*/
public class DigestUtilsTests {
@@ -38,24 +41,39 @@ public class DigestUtilsTests {
@Test
- public void md5() {
- byte[] result = DigestUtils.md5Digest(bytes);
+ public void md5() throws IOException {
byte[] expected = new byte[]
{-0x4f, 0xa, -0x73, -0x4f, 0x64, -0x20, 0x75, 0x41, 0x5, -0x49, -0x57, -0x65, -0x19, 0x2e, 0x3f, -0x1b};
+
+ byte[] result = DigestUtils.md5Digest(bytes);
+ assertArrayEquals("Invalid hash", expected, result);
+
+ result = DigestUtils.md5Digest(new ByteArrayInputStream(bytes));
assertArrayEquals("Invalid hash", expected, result);
}
@Test
- public void md5Hex() throws UnsupportedEncodingException {
+ public void md5Hex() throws IOException {
+ String expected = "b10a8db164e0754105b7a99be72e3fe5";
+
String hash = DigestUtils.md5DigestAsHex(bytes);
- assertEquals("Invalid hash", "b10a8db164e0754105b7a99be72e3fe5", hash);
+ assertEquals("Invalid hash", expected, hash);
+
+ hash = DigestUtils.md5DigestAsHex(new ByteArrayInputStream(bytes));
+ assertEquals("Invalid hash", expected, hash);
}
@Test
- public void md5StringBuilder() throws UnsupportedEncodingException {
+ public void md5StringBuilder() throws IOException {
+ String expected = "b10a8db164e0754105b7a99be72e3fe5";
+
StringBuilder builder = new StringBuilder();
DigestUtils.appendMd5DigestAsHex(bytes, builder);
- assertEquals("Invalid hash", "b10a8db164e0754105b7a99be72e3fe5", builder.toString());
+ assertEquals("Invalid hash", expected, builder.toString());
+
+ builder = new StringBuilder();
+ DigestUtils.appendMd5DigestAsHex(new ByteArrayInputStream(bytes), builder);
+ assertEquals("Invalid hash", expected, builder.toString());
}
}
diff --git a/spring-core/src/test/java/org/springframework/util/LinkedCaseInsensitiveMapTests.java b/spring-core/src/test/java/org/springframework/util/LinkedCaseInsensitiveMapTests.java
index 4f4492ef..16e3e29c 100644
--- a/spring-core/src/test/java/org/springframework/util/LinkedCaseInsensitiveMapTests.java
+++ b/spring-core/src/test/java/org/springframework/util/LinkedCaseInsensitiveMapTests.java
@@ -74,4 +74,26 @@ public class LinkedCaseInsensitiveMapTests {
assertEquals("N", map.getOrDefault(new Object(), "N"));
}
+ @Test
+ @SuppressWarnings("unchecked")
+ public void mapClone() {
+ map.put("key", "value1");
+ LinkedCaseInsensitiveMap<String> copy = (LinkedCaseInsensitiveMap<String>) map.clone();
+ assertEquals("value1", map.get("key"));
+ assertEquals("value1", map.get("KEY"));
+ assertEquals("value1", map.get("Key"));
+ assertEquals("value1", copy.get("key"));
+ assertEquals("value1", copy.get("KEY"));
+ assertEquals("value1", copy.get("Key"));
+ copy.put("Key", "value2");
+ assertEquals(1, map.size());
+ assertEquals(1, copy.size());
+ assertEquals("value1", map.get("key"));
+ assertEquals("value1", map.get("KEY"));
+ assertEquals("value1", map.get("Key"));
+ assertEquals("value2", copy.get("key"));
+ assertEquals("value2", copy.get("KEY"));
+ assertEquals("value2", copy.get("Key"));
+ }
+
}
diff --git a/spring-core/src/test/java/org/springframework/util/MimeTypeTests.java b/spring-core/src/test/java/org/springframework/util/MimeTypeTests.java
index b9d3480f..99c5a826 100644
--- a/spring-core/src/test/java/org/springframework/util/MimeTypeTests.java
+++ b/spring-core/src/test/java/org/springframework/util/MimeTypeTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2015 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -75,7 +75,7 @@ public class MimeTypeTests {
MimeType mimeType = MimeType.valueOf(s);
assertEquals("Invalid type", "text", mimeType.getType());
assertEquals("Invalid subtype", "html", mimeType.getSubtype());
- assertEquals("Invalid charset", Charset.forName("ISO-8859-1"), mimeType.getCharSet());
+ assertEquals("Invalid charset", Charset.forName("ISO-8859-1"), mimeType.getCharset());
}
@Test
@@ -84,7 +84,7 @@ public class MimeTypeTests {
MimeType mimeType = MimeType.valueOf(s);
assertEquals("Invalid type", "application", mimeType.getType());
assertEquals("Invalid subtype", "xml", mimeType.getSubtype());
- assertEquals("Invalid charset", Charset.forName("UTF-8"), mimeType.getCharSet());
+ assertEquals("Invalid charset", Charset.forName("UTF-8"), mimeType.getCharset());
}
@Test
@@ -190,6 +190,11 @@ public class MimeTypeTests {
}
@Test(expected = InvalidMimeTypeException.class)
+ public void parseMimeTypeMissingTypeAndSubtype() throws Exception {
+ MimeTypeUtils.parseMimeType(" ;a=b");
+ }
+
+ @Test(expected = InvalidMimeTypeException.class)
public void parseMimeTypeEmptyParameterAttribute() {
MimeTypeUtils.parseMimeType("audio/*;=value");
}
@@ -263,13 +268,13 @@ public class MimeTypeTests {
assertTrue("Invalid comparison result", audioBasicLevel.compareTo(audio) > 0);
- List<MimeType> expected = new ArrayList<MimeType>();
+ List<MimeType> expected = new ArrayList<>();
expected.add(audio);
expected.add(audioBasic);
expected.add(audioBasicLevel);
expected.add(audioWave);
- List<MimeType> result = new ArrayList<MimeType>(expected);
+ List<MimeType> result = new ArrayList<>(expected);
Random rnd = new Random();
// shuffle & sort 10 times
for (int i = 0; i < 10; i++) {
diff --git a/spring-core/src/test/java/org/springframework/util/NumberUtilsTests.java b/spring-core/src/test/java/org/springframework/util/NumberUtilsTests.java
index d6fbc9b0..2584cf42 100644
--- a/spring-core/src/test/java/org/springframework/util/NumberUtilsTests.java
+++ b/spring-core/src/test/java/org/springframework/util/NumberUtilsTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2015 the original author or authors.
+ * Copyright 2002-2016 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.
@@ -328,8 +328,6 @@ public class NumberUtilsTests {
assertEquals(Integer.valueOf(Integer.MIN_VALUE), NumberUtils.convertNumberToTargetClass(BigInteger.valueOf(Integer.MAX_VALUE + 1), Integer.class));
assertEquals(Integer.valueOf(Integer.MIN_VALUE), NumberUtils.convertNumberToTargetClass(BigInteger.valueOf(Integer.MIN_VALUE), Integer.class));
assertEquals(Integer.valueOf(Integer.MAX_VALUE), NumberUtils.convertNumberToTargetClass(BigInteger.valueOf(Integer.MIN_VALUE - 1), Integer.class));
- assertToNumberOverflow(BigInteger.valueOf(Integer.MAX_VALUE).add(BigInteger.ONE), Integer.class);
- assertToNumberOverflow(BigInteger.valueOf(Integer.MIN_VALUE).subtract(BigInteger.ONE), Integer.class);
assertEquals(Integer.valueOf(Integer.valueOf(-1)), NumberUtils.convertNumberToTargetClass(Long.valueOf(-1), Integer.class));
assertEquals(Integer.valueOf(Integer.valueOf(0)), NumberUtils.convertNumberToTargetClass(Long.valueOf(0), Integer.class));
@@ -338,8 +336,6 @@ public class NumberUtilsTests {
assertEquals(Integer.valueOf(Integer.MIN_VALUE), NumberUtils.convertNumberToTargetClass(Long.valueOf(Integer.MAX_VALUE + 1), Integer.class));
assertEquals(Integer.valueOf(Integer.MIN_VALUE), NumberUtils.convertNumberToTargetClass(Long.valueOf(Integer.MIN_VALUE), Integer.class));
assertEquals(Integer.valueOf(Integer.MAX_VALUE), NumberUtils.convertNumberToTargetClass(Long.valueOf(Integer.MIN_VALUE - 1), Integer.class));
- assertToNumberOverflow(Long.valueOf(Long.MAX_VALUE + 1), Integer.class);
- assertToNumberOverflow(Long.valueOf(Long.MIN_VALUE - 1), Integer.class);
assertEquals(Integer.valueOf(Integer.valueOf(-1)), NumberUtils.convertNumberToTargetClass(Integer.valueOf(-1), Integer.class));
assertEquals(Integer.valueOf(Integer.valueOf(0)), NumberUtils.convertNumberToTargetClass(Integer.valueOf(0), Integer.class));
@@ -364,6 +360,12 @@ public class NumberUtilsTests {
assertEquals(Integer.valueOf(Byte.MIN_VALUE), NumberUtils.convertNumberToTargetClass(Byte.valueOf((byte) (Byte.MAX_VALUE + 1)), Integer.class));
assertEquals(Integer.valueOf(Byte.MIN_VALUE), NumberUtils.convertNumberToTargetClass(Byte.valueOf(Byte.MIN_VALUE), Integer.class));
assertEquals(Integer.valueOf(Byte.MAX_VALUE), NumberUtils.convertNumberToTargetClass(Byte.valueOf((byte) (Byte.MIN_VALUE - 1)), Integer.class));
+
+ assertToNumberOverflow(Long.valueOf(Long.MAX_VALUE + 1), Integer.class);
+ assertToNumberOverflow(Long.valueOf(Long.MIN_VALUE - 1), Integer.class);
+ assertToNumberOverflow(BigInteger.valueOf(Integer.MAX_VALUE).add(BigInteger.ONE), Integer.class);
+ assertToNumberOverflow(BigInteger.valueOf(Integer.MIN_VALUE).subtract(BigInteger.ONE), Integer.class);
+ assertToNumberOverflow(new BigDecimal("18446744073709551611"), Integer.class);
}
@Test
@@ -376,9 +378,6 @@ public class NumberUtilsTests {
assertEquals(Long.valueOf(Long.MIN_VALUE), NumberUtils.convertNumberToTargetClass(BigInteger.valueOf(Long.MIN_VALUE), Long.class));
assertEquals(Long.valueOf(Long.MAX_VALUE), NumberUtils.convertNumberToTargetClass(BigInteger.valueOf(Long.MIN_VALUE - 1), Long.class));
- assertToNumberOverflow(BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE), Long.class);
- assertToNumberOverflow(BigInteger.valueOf(Long.MIN_VALUE).subtract(BigInteger.ONE), Long.class);
-
assertEquals(Long.valueOf(Long.valueOf(-1)), NumberUtils.convertNumberToTargetClass(Long.valueOf(-1), Long.class));
assertEquals(Long.valueOf(Long.valueOf(0)), NumberUtils.convertNumberToTargetClass(Long.valueOf(0), Long.class));
assertEquals(Long.valueOf(Long.valueOf(1)), NumberUtils.convertNumberToTargetClass(Long.valueOf(1), Long.class));
@@ -410,6 +409,10 @@ public class NumberUtilsTests {
assertEquals(Long.valueOf(Byte.MIN_VALUE), NumberUtils.convertNumberToTargetClass(Byte.valueOf((byte) (Byte.MAX_VALUE + 1)), Long.class));
assertEquals(Long.valueOf(Byte.MIN_VALUE), NumberUtils.convertNumberToTargetClass(Byte.valueOf(Byte.MIN_VALUE), Long.class));
assertEquals(Long.valueOf(Byte.MAX_VALUE), NumberUtils.convertNumberToTargetClass(Byte.valueOf((byte) (Byte.MIN_VALUE - 1)), Long.class));
+
+ assertToNumberOverflow(BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE), Long.class);
+ assertToNumberOverflow(BigInteger.valueOf(Long.MIN_VALUE).subtract(BigInteger.ONE), Long.class);
+ assertToNumberOverflow(new BigDecimal("18446744073709551611"), Long.class);
}
diff --git a/spring-core/src/test/java/org/springframework/util/ResizableByteArrayOutputStreamTests.java b/spring-core/src/test/java/org/springframework/util/ResizableByteArrayOutputStreamTests.java
index ec41e815..709b3fb0 100644
--- a/spring-core/src/test/java/org/springframework/util/ResizableByteArrayOutputStreamTests.java
+++ b/spring-core/src/test/java/org/springframework/util/ResizableByteArrayOutputStreamTests.java
@@ -54,7 +54,7 @@ public class ResizableByteArrayOutputStreamTests {
@Test
public void autoGrow() {
assertEquals(INITIAL_CAPACITY, this.baos.capacity());
- for(int i = 0; i < 129; i++) {
+ for (int i = 0; i < 129; i++) {
this.baos.write(0);
}
assertEquals(256, this.baos.capacity());
diff --git a/spring-core/src/test/java/org/springframework/util/StreamUtilsTests.java b/spring-core/src/test/java/org/springframework/util/StreamUtilsTests.java
index 93295cad..48f173f2 100644
--- a/spring-core/src/test/java/org/springframework/util/StreamUtilsTests.java
+++ b/spring-core/src/test/java/org/springframework/util/StreamUtilsTests.java
@@ -21,6 +21,7 @@ import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
+import java.util.Arrays;
import java.util.Random;
import java.util.UUID;
@@ -94,6 +95,15 @@ public class StreamUtilsTests {
}
@Test
+ public void copyRange() throws Exception {
+ ByteArrayOutputStream out = spy(new ByteArrayOutputStream());
+ StreamUtils.copyRange(new ByteArrayInputStream(bytes), out, 0, 100);
+ byte[] range = Arrays.copyOfRange(bytes, 0, 101);
+ assertThat(out.toByteArray(), equalTo(range));
+ verify(out, never()).close();
+ }
+
+ @Test
public void nonClosingInputStream() throws Exception {
InputStream source = mock(InputStream.class);
InputStream nonClosing = StreamUtils.nonClosing(source);
diff --git a/spring-core/src/test/java/org/springframework/util/xml/AbstractStaxHandlerTestCase.java b/spring-core/src/test/java/org/springframework/util/xml/AbstractStaxHandlerTestCase.java
index 8dd82430..e23c92cc 100644
--- a/spring-core/src/test/java/org/springframework/util/xml/AbstractStaxHandlerTestCase.java
+++ b/spring-core/src/test/java/org/springframework/util/xml/AbstractStaxHandlerTestCase.java
@@ -82,7 +82,7 @@ public abstract class AbstractStaxHandlerTestCase {
private static boolean wwwSpringframeworkOrgIsAccessible() {
try {
- new Socket("www.springframework.org", 80);
+ new Socket("www.springframework.org", 80).close();
}
catch (Exception e) {
return false;
diff --git a/spring-core/src/test/java/org/springframework/util/xml/AbstractStaxXMLReaderTestCase.java b/spring-core/src/test/java/org/springframework/util/xml/AbstractStaxXMLReaderTestCase.java
index 9dec693d..41aa5f25 100644
--- a/spring-core/src/test/java/org/springframework/util/xml/AbstractStaxXMLReaderTestCase.java
+++ b/spring-core/src/test/java/org/springframework/util/xml/AbstractStaxXMLReaderTestCase.java
@@ -194,8 +194,8 @@ public abstract class AbstractStaxXMLReaderTestCase {
private static class SkipLocatorArgumentsAdapter implements InvocationArgumentsAdapter {
@Override
public Object[] adaptArguments(Object[] arguments) {
- for(int i=0; i<arguments.length; i++) {
- if(arguments[i] instanceof Locator) {
+ for (int i = 0; i < arguments.length; i++) {
+ if (arguments[i] instanceof Locator) {
arguments[i] = null;
}
}
@@ -206,7 +206,7 @@ public abstract class AbstractStaxXMLReaderTestCase {
private static class CharArrayToStringAdapter implements InvocationArgumentsAdapter {
@Override
public Object[] adaptArguments(Object[] arguments) {
- if(arguments.length == 3 && arguments[0] instanceof char[]
+ if (arguments.length == 3 && arguments[0] instanceof char[]
&& arguments[1] instanceof Integer && arguments[2] instanceof Integer) {
return new Object[] {new String((char[]) arguments[0], (Integer) arguments[1], (Integer) arguments[2])};
}
@@ -218,7 +218,7 @@ public abstract class AbstractStaxXMLReaderTestCase {
@Override
public Object[] adaptArguments(Object[] arguments) {
for (int i = 0; i < arguments.length; i++) {
- if(arguments[i] instanceof Attributes) {
+ if (arguments[i] instanceof Attributes) {
arguments[i] = new PartialAttributes((Attributes) arguments[i]);
}
};