Test for <util:map> with LinkedCaseInsensitiveMap and specified key/value types, with corresponding 3.2.x fix
Issue: SPR-10994
(cherry picked from commit de8645b)
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -17,14 +17,15 @@
|
||||
package org.springframework.beans.factory.xml;
|
||||
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.Arrays;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.config.FieldRetrievingFactoryBean;
|
||||
import org.springframework.beans.factory.config.PropertiesFactoryBean;
|
||||
@@ -35,19 +36,23 @@ import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.tests.beans.CollectingReaderEventListener;
|
||||
import org.springframework.tests.sample.beans.CustomEnum;
|
||||
import org.springframework.tests.sample.beans.TestBean;
|
||||
import org.springframework.util.LinkedCaseInsensitiveMap;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Rob Harrop
|
||||
* @author Juergen Hoeller
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class UtilNamespaceHandlerTests extends TestCase {
|
||||
public class UtilNamespaceHandlerTests {
|
||||
|
||||
private DefaultListableBeanFactory beanFactory;
|
||||
|
||||
private CollectingReaderEventListener listener = new CollectingReaderEventListener();
|
||||
|
||||
@Override
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
this.beanFactory = new DefaultListableBeanFactory();
|
||||
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this.beanFactory);
|
||||
@@ -55,17 +60,21 @@ public class UtilNamespaceHandlerTests extends TestCase {
|
||||
reader.loadBeanDefinitions(new ClassPathResource("testUtilNamespace.xml", getClass()));
|
||||
}
|
||||
|
||||
public void testConstant() throws Exception {
|
||||
|
||||
@Test
|
||||
public void testConstant() {
|
||||
Integer min = (Integer) this.beanFactory.getBean("min");
|
||||
assertEquals(Integer.MIN_VALUE, min.intValue());
|
||||
}
|
||||
|
||||
public void testConstantWithDefaultName() throws Exception {
|
||||
@Test
|
||||
public void testConstantWithDefaultName() {
|
||||
Integer max = (Integer) this.beanFactory.getBean("java.lang.Integer.MAX_VALUE");
|
||||
assertEquals(Integer.MAX_VALUE, max.intValue());
|
||||
}
|
||||
|
||||
public void testEvents() throws Exception {
|
||||
@Test
|
||||
public void testEvents() {
|
||||
ComponentDefinition propertiesComponent = this.listener.getComponentDefinition("myProperties");
|
||||
assertNotNull("Event for 'myProperties' not sent", propertiesComponent);
|
||||
AbstractBeanDefinition propertiesBean = (AbstractBeanDefinition) propertiesComponent.getBeanDefinitions()[0];
|
||||
@@ -77,30 +86,35 @@ public class UtilNamespaceHandlerTests extends TestCase {
|
||||
assertEquals("Incorrect BeanDefinition", FieldRetrievingFactoryBean.class, constantBean.getBeanClass());
|
||||
}
|
||||
|
||||
public void testNestedProperties() throws Exception {
|
||||
@Test
|
||||
public void testNestedProperties() {
|
||||
TestBean bean = (TestBean) this.beanFactory.getBean("testBean");
|
||||
Properties props = bean.getSomeProperties();
|
||||
assertEquals("Incorrect property value", "bar", props.get("foo"));
|
||||
}
|
||||
|
||||
public void testPropertyPath() throws Exception {
|
||||
@Test
|
||||
public void testPropertyPath() {
|
||||
String name = (String) this.beanFactory.getBean("name");
|
||||
assertEquals("Rob Harrop", name);
|
||||
}
|
||||
|
||||
public void testNestedPropertyPath() throws Exception {
|
||||
@Test
|
||||
public void testNestedPropertyPath() {
|
||||
TestBean bean = (TestBean) this.beanFactory.getBean("testBean");
|
||||
assertEquals("Rob Harrop", bean.getName());
|
||||
}
|
||||
|
||||
public void testSimpleMap() throws Exception {
|
||||
@Test
|
||||
public void testSimpleMap() {
|
||||
Map map = (Map) this.beanFactory.getBean("simpleMap");
|
||||
assertEquals("bar", map.get("foo"));
|
||||
Map map2 = (Map) this.beanFactory.getBean("simpleMap");
|
||||
assertTrue(map == map2);
|
||||
}
|
||||
|
||||
public void testScopedMap() throws Exception {
|
||||
@Test
|
||||
public void testScopedMap() {
|
||||
Map map = (Map) this.beanFactory.getBean("scopedMap");
|
||||
assertEquals("bar", map.get("foo"));
|
||||
Map map2 = (Map) this.beanFactory.getBean("scopedMap");
|
||||
@@ -108,14 +122,16 @@ public class UtilNamespaceHandlerTests extends TestCase {
|
||||
assertTrue(map != map2);
|
||||
}
|
||||
|
||||
public void testSimpleList() throws Exception {
|
||||
@Test
|
||||
public void testSimpleList() {
|
||||
List list = (List) this.beanFactory.getBean("simpleList");
|
||||
assertEquals("Rob Harrop", list.get(0));
|
||||
List list2 = (List) this.beanFactory.getBean("simpleList");
|
||||
assertTrue(list == list2);
|
||||
}
|
||||
|
||||
public void testScopedList() throws Exception {
|
||||
@Test
|
||||
public void testScopedList() {
|
||||
List list = (List) this.beanFactory.getBean("scopedList");
|
||||
assertEquals("Rob Harrop", list.get(0));
|
||||
List list2 = (List) this.beanFactory.getBean("scopedList");
|
||||
@@ -123,14 +139,16 @@ public class UtilNamespaceHandlerTests extends TestCase {
|
||||
assertTrue(list != list2);
|
||||
}
|
||||
|
||||
public void testSimpleSet() throws Exception {
|
||||
@Test
|
||||
public void testSimpleSet() {
|
||||
Set set = (Set) this.beanFactory.getBean("simpleSet");
|
||||
assertTrue(set.contains("Rob Harrop"));
|
||||
Set set2 = (Set) this.beanFactory.getBean("simpleSet");
|
||||
assertTrue(set == set2);
|
||||
}
|
||||
|
||||
public void testScopedSet() throws Exception {
|
||||
@Test
|
||||
public void testScopedSet() {
|
||||
Set set = (Set) this.beanFactory.getBean("scopedSet");
|
||||
assertTrue(set.contains("Rob Harrop"));
|
||||
Set set2 = (Set) this.beanFactory.getBean("scopedSet");
|
||||
@@ -138,13 +156,22 @@ public class UtilNamespaceHandlerTests extends TestCase {
|
||||
assertTrue(set != set2);
|
||||
}
|
||||
|
||||
public void testMapWithRef() throws Exception {
|
||||
@Test
|
||||
public void testMapWithRef() {
|
||||
Map map = (Map) this.beanFactory.getBean("mapWithRef");
|
||||
assertTrue(map instanceof TreeMap);
|
||||
assertEquals(this.beanFactory.getBean("testBean"), map.get("bean"));
|
||||
}
|
||||
|
||||
public void testNestedCollections() throws Exception {
|
||||
@Test
|
||||
public void testMapWithTypes() {
|
||||
Map map = (Map) this.beanFactory.getBean("mapWithTypes");
|
||||
assertTrue(map instanceof LinkedCaseInsensitiveMap);
|
||||
assertEquals(this.beanFactory.getBean("testBean"), map.get("bean"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNestedCollections() {
|
||||
TestBean bean = (TestBean) this.beanFactory.getBean("nestedCollectionsBean");
|
||||
|
||||
List list = bean.getSomeList();
|
||||
@@ -171,7 +198,8 @@ public class UtilNamespaceHandlerTests extends TestCase {
|
||||
assertFalse(map == bean2.getSomeMap());
|
||||
}
|
||||
|
||||
public void testNestedShortcutCollections() throws Exception {
|
||||
@Test
|
||||
public void testNestedShortcutCollections() {
|
||||
TestBean bean = (TestBean) this.beanFactory.getBean("nestedShortcutCollections");
|
||||
|
||||
assertEquals(1, bean.getStringArray().length);
|
||||
@@ -194,7 +222,8 @@ public class UtilNamespaceHandlerTests extends TestCase {
|
||||
assertFalse(set == bean2.getSomeSet());
|
||||
}
|
||||
|
||||
public void testNestedInCollections() throws Exception {
|
||||
@Test
|
||||
public void testNestedInCollections() {
|
||||
TestBean bean = (TestBean) this.beanFactory.getBean("nestedCustomTagBean");
|
||||
|
||||
List list = bean.getSomeList();
|
||||
@@ -219,7 +248,8 @@ public class UtilNamespaceHandlerTests extends TestCase {
|
||||
assertFalse(map == bean2.getSomeMap());
|
||||
}
|
||||
|
||||
public void testCircularCollections() throws Exception {
|
||||
@Test
|
||||
public void testCircularCollections() {
|
||||
TestBean bean = (TestBean) this.beanFactory.getBean("circularCollectionsBean");
|
||||
|
||||
List list = bean.getSomeList();
|
||||
@@ -235,7 +265,8 @@ public class UtilNamespaceHandlerTests extends TestCase {
|
||||
assertEquals(bean, map.get("foo"));
|
||||
}
|
||||
|
||||
public void testCircularCollectionBeansStartingWithList() throws Exception {
|
||||
@Test
|
||||
public void testCircularCollectionBeansStartingWithList() {
|
||||
this.beanFactory.getBean("circularList");
|
||||
TestBean bean = (TestBean) this.beanFactory.getBean("circularCollectionBeansBean");
|
||||
|
||||
@@ -255,7 +286,8 @@ public class UtilNamespaceHandlerTests extends TestCase {
|
||||
assertEquals(bean, map.get("foo"));
|
||||
}
|
||||
|
||||
public void testCircularCollectionBeansStartingWithSet() throws Exception {
|
||||
@Test
|
||||
public void testCircularCollectionBeansStartingWithSet() {
|
||||
this.beanFactory.getBean("circularSet");
|
||||
TestBean bean = (TestBean) this.beanFactory.getBean("circularCollectionBeansBean");
|
||||
|
||||
@@ -275,7 +307,8 @@ public class UtilNamespaceHandlerTests extends TestCase {
|
||||
assertEquals(bean, map.get("foo"));
|
||||
}
|
||||
|
||||
public void testCircularCollectionBeansStartingWithMap() throws Exception {
|
||||
@Test
|
||||
public void testCircularCollectionBeansStartingWithMap() {
|
||||
this.beanFactory.getBean("circularMap");
|
||||
TestBean bean = (TestBean) this.beanFactory.getBean("circularCollectionBeansBean");
|
||||
|
||||
@@ -295,12 +328,14 @@ public class UtilNamespaceHandlerTests extends TestCase {
|
||||
assertEquals(bean, map.get("foo"));
|
||||
}
|
||||
|
||||
public void testNestedInConstructor() throws Exception {
|
||||
@Test
|
||||
public void testNestedInConstructor() {
|
||||
TestBean bean = (TestBean) this.beanFactory.getBean("constructedTestBean");
|
||||
assertEquals("Rob Harrop", bean.getName());
|
||||
}
|
||||
|
||||
public void testLoadProperties() throws Exception {
|
||||
@Test
|
||||
public void testLoadProperties() {
|
||||
Properties props = (Properties) this.beanFactory.getBean("myProperties");
|
||||
assertEquals("Incorrect property value", "bar", props.get("foo"));
|
||||
assertEquals("Incorrect property value", null, props.get("foo2"));
|
||||
@@ -308,7 +343,8 @@ public class UtilNamespaceHandlerTests extends TestCase {
|
||||
assertTrue(props == props2);
|
||||
}
|
||||
|
||||
public void testScopedProperties() throws Exception {
|
||||
@Test
|
||||
public void testScopedProperties() {
|
||||
Properties props = (Properties) this.beanFactory.getBean("myScopedProperties");
|
||||
assertEquals("Incorrect property value", "bar", props.get("foo"));
|
||||
assertEquals("Incorrect property value", null, props.get("foo2"));
|
||||
@@ -318,30 +354,35 @@ public class UtilNamespaceHandlerTests extends TestCase {
|
||||
assertTrue(props != props2);
|
||||
}
|
||||
|
||||
public void testLocalProperties() throws Exception {
|
||||
@Test
|
||||
public void testLocalProperties() {
|
||||
Properties props = (Properties) this.beanFactory.getBean("myLocalProperties");
|
||||
assertEquals("Incorrect property value", null, props.get("foo"));
|
||||
assertEquals("Incorrect property value", "bar2", props.get("foo2"));
|
||||
}
|
||||
|
||||
public void testMergedProperties() throws Exception {
|
||||
@Test
|
||||
public void testMergedProperties() {
|
||||
Properties props = (Properties) this.beanFactory.getBean("myMergedProperties");
|
||||
assertEquals("Incorrect property value", "bar", props.get("foo"));
|
||||
assertEquals("Incorrect property value", "bar2", props.get("foo2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocalOverrideDefault() {
|
||||
Properties props = (Properties) this.beanFactory.getBean("defaultLocalOverrideProperties");
|
||||
assertEquals("Incorrect property value", "bar", props.get("foo"));
|
||||
assertEquals("Incorrect property value", "local2", props.get("foo2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocalOverrideFalse() {
|
||||
Properties props = (Properties) this.beanFactory.getBean("falseLocalOverrideProperties");
|
||||
assertEquals("Incorrect property value", "bar", props.get("foo"));
|
||||
assertEquals("Incorrect property value", "local2", props.get("foo2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocalOverrideTrue() {
|
||||
Properties props = (Properties) this.beanFactory.getBean("trueLocalOverrideProperties");
|
||||
assertEquals("Incorrect property value", "local", props.get("foo"));
|
||||
|
||||
@@ -49,6 +49,11 @@
|
||||
<entry key="bean" value-ref="testBean"/>
|
||||
</util:map>
|
||||
|
||||
<util:map id="mapWithTypes" map-class="org.springframework.util.LinkedCaseInsensitiveMap"
|
||||
key-type="java.lang.String" value-type="org.springframework.tests.sample.beans.TestBean">
|
||||
<entry key="bean" value-ref="testBean"/>
|
||||
</util:map>
|
||||
|
||||
<util:list id="simpleList">
|
||||
<value>Rob Harrop</value>
|
||||
</util:list>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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,7 +44,7 @@ public class TypeDescriptor implements Serializable {
|
||||
|
||||
static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
|
||||
|
||||
private static final Map<Class<?>, TypeDescriptor> typeDescriptorCache = new HashMap<Class<?>, TypeDescriptor>();
|
||||
private static final Map<Class<?>, TypeDescriptor> typeDescriptorCache = new HashMap<Class<?>, TypeDescriptor>(18);
|
||||
|
||||
static {
|
||||
typeDescriptorCache.put(boolean.class, new TypeDescriptor(boolean.class));
|
||||
@@ -53,17 +53,18 @@ public class TypeDescriptor implements Serializable {
|
||||
typeDescriptorCache.put(Byte.class, new TypeDescriptor(Byte.class));
|
||||
typeDescriptorCache.put(char.class, new TypeDescriptor(char.class));
|
||||
typeDescriptorCache.put(Character.class, new TypeDescriptor(Character.class));
|
||||
typeDescriptorCache.put(short.class, new TypeDescriptor(short.class));
|
||||
typeDescriptorCache.put(Short.class, new TypeDescriptor(Short.class));
|
||||
typeDescriptorCache.put(double.class, new TypeDescriptor(double.class));
|
||||
typeDescriptorCache.put(Double.class, new TypeDescriptor(Double.class));
|
||||
typeDescriptorCache.put(int.class, new TypeDescriptor(int.class));
|
||||
typeDescriptorCache.put(Integer.class, new TypeDescriptor(Integer.class));
|
||||
typeDescriptorCache.put(long.class, new TypeDescriptor(long.class));
|
||||
typeDescriptorCache.put(Long.class, new TypeDescriptor(Long.class));
|
||||
typeDescriptorCache.put(float.class, new TypeDescriptor(float.class));
|
||||
typeDescriptorCache.put(Float.class, new TypeDescriptor(Float.class));
|
||||
typeDescriptorCache.put(double.class, new TypeDescriptor(double.class));
|
||||
typeDescriptorCache.put(Double.class, new TypeDescriptor(Double.class));
|
||||
typeDescriptorCache.put(short.class, new TypeDescriptor(short.class));
|
||||
typeDescriptorCache.put(Short.class, new TypeDescriptor(Short.class));
|
||||
typeDescriptorCache.put(String.class, new TypeDescriptor(String.class));
|
||||
typeDescriptorCache.put(Object.class, new TypeDescriptor(Object.class));
|
||||
}
|
||||
|
||||
|
||||
@@ -119,6 +120,9 @@ public class TypeDescriptor implements Serializable {
|
||||
* @return the type descriptor
|
||||
*/
|
||||
public static TypeDescriptor valueOf(Class<?> type) {
|
||||
if (type == null) {
|
||||
type = Object.class;
|
||||
}
|
||||
TypeDescriptor desc = typeDescriptorCache.get(type);
|
||||
return (desc != null ? desc : new TypeDescriptor(type));
|
||||
}
|
||||
@@ -145,8 +149,10 @@ public class TypeDescriptor implements Serializable {
|
||||
/**
|
||||
* Create a new type descriptor from a {@link java.util.Map} type.
|
||||
* <p>Useful for converting to typed Maps.
|
||||
* <p>For example, a Map<String, String> could be converted to a Map<Id, EmailAddress> by converting to a targetType built with this method:
|
||||
* The method call to construct such a TypeDescriptor would look something like: map(Map.class, TypeDescriptor.valueOf(Id.class), TypeDescriptor.valueOf(EmailAddress.class));
|
||||
* <p>For example, a Map<String, String> could be converted to a Map<Id, EmailAddress>
|
||||
* by converting to a targetType built with this method:
|
||||
* The method call to construct such a TypeDescriptor would look something like:
|
||||
* map(Map.class, TypeDescriptor.valueOf(Id.class), TypeDescriptor.valueOf(EmailAddress.class));
|
||||
* @param mapType the map type, which must implement {@link Map}
|
||||
* @param keyTypeDescriptor a descriptor for the map's key type, used to convert map keys
|
||||
* @param valueTypeDescriptor the map's value type, used to convert map values
|
||||
@@ -168,7 +174,7 @@ public class TypeDescriptor implements Serializable {
|
||||
* @since 3.2.1
|
||||
*/
|
||||
public static TypeDescriptor array(TypeDescriptor elementTypeDescriptor) {
|
||||
if(elementTypeDescriptor == null) {
|
||||
if (elementTypeDescriptor == null) {
|
||||
return null;
|
||||
}
|
||||
Class<?> type = Array.newInstance(elementTypeDescriptor.getType(), 0).getClass();
|
||||
@@ -194,13 +200,13 @@ public class TypeDescriptor implements Serializable {
|
||||
* @return the nested type descriptor at the specified nesting level, or null
|
||||
* if it could not be obtained
|
||||
* @throws IllegalArgumentException if the nesting level of the input
|
||||
* {@link MethodParameter} argument is not 1
|
||||
* @throws IllegalArgumentException if the types up to the specified nesting
|
||||
* level are not of collection, array, or map types
|
||||
* {@link MethodParameter} argument is not 1, or if the types up to the
|
||||
* specified nesting level are not of collection, array, or map types
|
||||
*/
|
||||
public static TypeDescriptor nested(MethodParameter methodParameter, int nestingLevel) {
|
||||
if (methodParameter.getNestingLevel() != 1) {
|
||||
throw new IllegalArgumentException("methodParameter nesting level must be 1: use the nestingLevel parameter to specify the desired nestingLevel for nested type traversal");
|
||||
throw new IllegalArgumentException("methodParameter nesting level must be 1: " +
|
||||
"use the nestingLevel parameter to specify the desired nestingLevel for nested type traversal");
|
||||
}
|
||||
return nested(new ParameterDescriptor(methodParameter), nestingLevel);
|
||||
}
|
||||
@@ -256,8 +262,10 @@ public class TypeDescriptor implements Serializable {
|
||||
|
||||
/**
|
||||
* Create a new type descriptor for an object.
|
||||
* <p>Use this factory method to introspect a source object before asking the conversion system to convert it to some another type.
|
||||
* <p>If the provided object is null, returns null, else calls {@link #valueOf(Class)} to build a TypeDescriptor from the object's class.
|
||||
* <p>Use this factory method to introspect a source object before asking the
|
||||
* conversion system to convert it to some another type.
|
||||
* <p>If the provided object is null, returns null, else calls {@link #valueOf(Class)}
|
||||
* to build a TypeDescriptor from the object's class.
|
||||
* @param source the source object
|
||||
* @return the type descriptor
|
||||
*/
|
||||
@@ -265,6 +273,7 @@ public class TypeDescriptor implements Serializable {
|
||||
return (source != null ? valueOf(source.getClass()) : null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The type of the backing class, method parameter, field, or property described by this TypeDescriptor.
|
||||
* <p>Returns primitive types as-is.
|
||||
@@ -290,10 +299,11 @@ public class TypeDescriptor implements Serializable {
|
||||
* Narrows this {@link TypeDescriptor} by setting its type to the class of the provided value.
|
||||
* <p>If the value is {@code null}, no narrowing is performed and this TypeDescriptor is returned unchanged.
|
||||
* <p>Designed to be called by binding frameworks when they read property, field, or method return values.
|
||||
* Allows such frameworks to narrow a TypeDescriptor built from a declared property, field, or method return value type.
|
||||
* For example, a field declared as {@code java.lang.Object} would be narrowed to {@code java.util.HashMap}
|
||||
* if it was set to a {@code java.util.HashMap} value. The narrowed TypeDescriptor can then be used to convert
|
||||
* the HashMap to some other type. Annotation and nested type context is preserved by the narrowed copy.
|
||||
* Allows such frameworks to narrow a TypeDescriptor built from a declared property, field, or method return
|
||||
* value type. For example, a field declared as {@code java.lang.Object} would be narrowed to
|
||||
* {@code java.util.HashMap} if it was set to a {@code java.util.HashMap} value. The narrowed
|
||||
* TypeDescriptor can then be used to convert the HashMap to some other type. Annotation and
|
||||
* nested type context is preserved by the narrowed copy.
|
||||
* @param value the value to use for narrowing this type descriptor
|
||||
* @return this TypeDescriptor narrowed (returns a copy with its type updated to the class of the provided value)
|
||||
*/
|
||||
@@ -375,12 +385,15 @@ public class TypeDescriptor implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if an object of this type descriptor can be assigned to the location described by the given type descriptor.
|
||||
* <p>For example, valueOf(String.class).isAssignableTo(valueOf(CharSequence.class)) returns true because a String value can be assigned to a CharSequence variable.
|
||||
* On the other hand, valueOf(Number.class).isAssignableTo(valueOf(Integer.class)) returns false because, while all Integers are Numbers, not all Numbers are Integers.
|
||||
* <p>
|
||||
* For arrays, collections, and maps, element and key/value types are checked if declared.
|
||||
* For example, a List<String> field value is assignable to a Collection<CharSequence> field, but List<Number> is not assignable to List<Integer>.
|
||||
* Returns true if an object of this type descriptor can be assigned to the location described by the
|
||||
* given type descriptor.
|
||||
* <p>For example, valueOf(String.class).isAssignableTo(valueOf(CharSequence.class)) returns true
|
||||
* because a String value can be assigned to a CharSequence variable. On the other hand,
|
||||
* valueOf(Number.class).isAssignableTo(valueOf(Integer.class)) returns false because,
|
||||
* while all Integers are Numbers, not all Numbers are Integers.
|
||||
* <p>For arrays, collections, and maps, element and key/value types are checked if declared.
|
||||
* For example, a List<String> field value is assignable to a Collection<CharSequence>
|
||||
* field, but List<Number> is not assignable to List<Integer>.
|
||||
* @return true if this type is assignable to the type represented by the provided type descriptor
|
||||
* @see #getObjectType()
|
||||
*/
|
||||
@@ -404,6 +417,7 @@ public class TypeDescriptor implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// indexable type descriptor operations
|
||||
|
||||
/**
|
||||
@@ -424,7 +438,8 @@ public class TypeDescriptor implements Serializable {
|
||||
* If this type is an array, returns the array's component type.
|
||||
* If this type is a {@link Collection} and it is parameterized, returns the Collection's element type.
|
||||
* If the Collection is not parameterized, returns null indicating the element type is not declared.
|
||||
* @return the array component type or Collection element type, or {@code null} if this type is a Collection but its element type is not parameterized
|
||||
* @return the array component type or Collection element type, or {@code null} if this type is a
|
||||
* Collection but its element type is not parameterized
|
||||
* @throws IllegalStateException if this type is not a java.util.Collection or Array type
|
||||
*/
|
||||
public TypeDescriptor getElementTypeDescriptor() {
|
||||
@@ -433,10 +448,13 @@ public class TypeDescriptor implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* If this type is a {@link Collection} or an Array, creates a element TypeDescriptor from the provided collection or array element.
|
||||
* <p>Narrows the {@link #getElementTypeDescriptor() elementType} property to the class of the provided collection or array element.
|
||||
* For example, if this describes a java.util.List<java.lang.Number< and the element argument is a java.lang.Integer, the returned TypeDescriptor will be java.lang.Integer.
|
||||
* If this describes a java.util.List<?> and the element argument is a java.lang.Integer, the returned TypeDescriptor will be java.lang.Integer as well.
|
||||
* If this type is a {@link Collection} or an Array, creates a element TypeDescriptor from the provided
|
||||
* collection or array element.
|
||||
* <p>Narrows the {@link #getElementTypeDescriptor() elementType} property to the class of the provided
|
||||
* collection or array element. For example, if this describes a java.util.List<java.lang.Number<
|
||||
* and the element argument is a java.lang.Integer, the returned TypeDescriptor will be java.lang.Integer.
|
||||
* If this describes a java.util.List<?> and the element argument is a java.lang.Integer, the returned
|
||||
* TypeDescriptor will be java.lang.Integer as well.
|
||||
* <p>Annotation and nested type context will be preserved in the narrowed TypeDescriptor that is returned.
|
||||
* @param element the collection or array element
|
||||
* @return a element type descriptor, narrowed to the type of the provided element
|
||||
@@ -447,6 +465,7 @@ public class TypeDescriptor implements Serializable {
|
||||
return narrow(element, getElementTypeDescriptor());
|
||||
}
|
||||
|
||||
|
||||
// map type descriptor operations
|
||||
|
||||
/**
|
||||
@@ -470,8 +489,10 @@ public class TypeDescriptor implements Serializable {
|
||||
/**
|
||||
* If this type is a {@link Map}, creates a mapKey {@link TypeDescriptor} from the provided map key.
|
||||
* <p>Narrows the {@link #getMapKeyTypeDescriptor() mapKeyType} property to the class of the provided map key.
|
||||
* For example, if this describes a java.util.Map<java.lang.Number, java.lang.String< and the key argument is a java.lang.Integer, the returned TypeDescriptor will be java.lang.Integer.
|
||||
* <p>If this describes a java.util.Map<?, ?> and the key argument is a java.lang.Integer, the returned TypeDescriptor will be java.lang.Integer as well.
|
||||
* For example, if this describes a java.util.Map<java.lang.Number, java.lang.String< and the key argument
|
||||
* is a java.lang.Integer, the returned TypeDescriptor will be java.lang.Integer.
|
||||
* <p>If this describes a java.util.Map<?, ?> and the key argument is a java.lang.Integer, the returned
|
||||
* TypeDescriptor will be java.lang.Integer as well.
|
||||
* <p>Annotation and nested type context will be preserved in the narrowed TypeDescriptor that is returned.
|
||||
* @param mapKey the map key
|
||||
* @return the map key type descriptor
|
||||
@@ -495,9 +516,11 @@ public class TypeDescriptor implements Serializable {
|
||||
|
||||
/**
|
||||
* If this type is a {@link Map}, creates a mapValue {@link TypeDescriptor} from the provided map value.
|
||||
* <p>Narrows the {@link #getMapValueTypeDescriptor() mapValueType} property to the class of the provided map value.
|
||||
* For example, if this describes a java.util.Map<java.lang.String, java.lang.Number< and the value argument is a java.lang.Integer, the returned TypeDescriptor will be java.lang.Integer.
|
||||
* If this describes a java.util.Map<?, ?> and the value argument is a java.lang.Integer, the returned TypeDescriptor will be java.lang.Integer as well.
|
||||
* <p>Narrows the {@link #getMapValueTypeDescriptor() mapValueType} property to the class of the provided
|
||||
* map value. For example, if this describes a java.util.Map<java.lang.String, java.lang.Number<
|
||||
* and the value argument is a java.lang.Integer, the returned TypeDescriptor will be java.lang.Integer.
|
||||
* If this describes a java.util.Map<?, ?> and the value argument is a java.lang.Integer, the
|
||||
* returned TypeDescriptor will be java.lang.Integer as well.
|
||||
* <p>Annotation and nested type context will be preserved in the narrowed TypeDescriptor that is returned.
|
||||
* @param mapValue the map value
|
||||
* @return the map value type descriptor
|
||||
@@ -511,7 +534,8 @@ public class TypeDescriptor implements Serializable {
|
||||
// deprecations in Spring 3.1
|
||||
|
||||
/**
|
||||
* Returns the value of {@link TypeDescriptor#getType() getType()} for the {@link #getElementTypeDescriptor() elementTypeDescriptor}.
|
||||
* Returns the value of {@link TypeDescriptor#getType() getType()} for the
|
||||
* {@link #getElementTypeDescriptor() elementTypeDescriptor}.
|
||||
* @deprecated in Spring 3.1 in favor of {@link #getElementTypeDescriptor()}
|
||||
* @throws IllegalStateException if this type is not a java.util.Collection or Array type
|
||||
*/
|
||||
@@ -521,7 +545,8 @@ public class TypeDescriptor implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of {@link TypeDescriptor#getType() getType()} for the {@link #getMapKeyTypeDescriptor() getMapKeyTypeDescriptor}.
|
||||
* Returns the value of {@link TypeDescriptor#getType() getType()} for the
|
||||
* {@link #getMapKeyTypeDescriptor() getMapKeyTypeDescriptor}.
|
||||
* @deprecated in Spring 3.1 in favor of {@link #getMapKeyTypeDescriptor()}
|
||||
* @throws IllegalStateException if this type is not a java.util.Map
|
||||
*/
|
||||
@@ -531,7 +556,8 @@ public class TypeDescriptor implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of {@link TypeDescriptor#getType() getType()} for the {@link #getMapValueTypeDescriptor() getMapValueTypeDescriptor}.
|
||||
* Returns the value of {@link TypeDescriptor#getType() getType()} for the
|
||||
* {@link #getMapValueTypeDescriptor() getMapValueTypeDescriptor}.
|
||||
* @deprecated in Spring 3.1 in favor of {@link #getMapValueTypeDescriptor()}
|
||||
* @throws IllegalStateException if this type is not a java.util.Map
|
||||
*/
|
||||
@@ -540,20 +566,6 @@ public class TypeDescriptor implements Serializable {
|
||||
return getMapValueTypeDescriptor().getType();
|
||||
}
|
||||
|
||||
// package private helpers
|
||||
|
||||
TypeDescriptor(AbstractDescriptor descriptor) {
|
||||
this.type = descriptor.getType();
|
||||
this.elementTypeDescriptor = descriptor.getElementTypeDescriptor();
|
||||
this.mapKeyTypeDescriptor = descriptor.getMapKeyTypeDescriptor();
|
||||
this.mapValueTypeDescriptor = descriptor.getMapValueTypeDescriptor();
|
||||
this.annotations = descriptor.getAnnotations();
|
||||
}
|
||||
|
||||
static Annotation[] nullSafeAnnotations(Annotation[] annotations) {
|
||||
return annotations != null ? annotations : EMPTY_ANNOTATION_ARRAY;
|
||||
}
|
||||
|
||||
|
||||
// internal constructors
|
||||
|
||||
@@ -579,6 +591,21 @@ public class TypeDescriptor implements Serializable {
|
||||
this.annotations = annotations;
|
||||
}
|
||||
|
||||
TypeDescriptor(AbstractDescriptor descriptor) {
|
||||
this.type = descriptor.getType();
|
||||
this.elementTypeDescriptor = descriptor.getElementTypeDescriptor();
|
||||
this.mapKeyTypeDescriptor = descriptor.getMapKeyTypeDescriptor();
|
||||
this.mapValueTypeDescriptor = descriptor.getMapValueTypeDescriptor();
|
||||
this.annotations = descriptor.getAnnotations();
|
||||
}
|
||||
|
||||
|
||||
// internal helpers
|
||||
|
||||
static Annotation[] nullSafeAnnotations(Annotation[] annotations) {
|
||||
return (annotations != null ? annotations : EMPTY_ANNOTATION_ARRAY);
|
||||
}
|
||||
|
||||
private static TypeDescriptor nested(AbstractDescriptor descriptor, int nestingLevel) {
|
||||
for (int i = 0; i < nestingLevel; i++) {
|
||||
descriptor = descriptor.nested();
|
||||
@@ -589,9 +616,6 @@ public class TypeDescriptor implements Serializable {
|
||||
return new TypeDescriptor(descriptor);
|
||||
}
|
||||
|
||||
|
||||
// internal helpers
|
||||
|
||||
private void assertCollectionOrArray() {
|
||||
if (!isCollection() && !isArray()) {
|
||||
throw new IllegalStateException("Not a java.util.Collection or Array");
|
||||
|
||||
Reference in New Issue
Block a user