TypeDescriptor cleanup and general polishing; fixed a number of bugs related to TypeDescriptor usage in client code across beans and spel packages

git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@3846 50f2f4bb-b051-0410-bef5-90022cba6387
This commit is contained in:
Keith Donald 2011-01-05 05:49:33 +00:00
parent dfb8b267ca
commit 1e2a8083a1
33 changed files with 449 additions and 539 deletions

View File

@ -369,10 +369,10 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
if (pd != null) { if (pd != null) {
Class type = getPropertyType(propertyName); Class type = getPropertyType(propertyName);
if (pd.getReadMethod() != null) { if (pd.getReadMethod() != null) {
return new PropertyTypeDescriptor(pd, new MethodParameter(pd.getReadMethod(), -1), type); return new PropertyTypeDescriptor(type, new MethodParameter(pd.getReadMethod(), -1), pd);
} }
else if (pd.getWriteMethod() != null) { else if (pd.getWriteMethod() != null) {
return new PropertyTypeDescriptor(pd, BeanUtils.getWriteMethodParameter(pd), type); return new PropertyTypeDescriptor(type, BeanUtils.getWriteMethodParameter(pd), pd);
} }
} }
} }
@ -468,12 +468,6 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
} }
} }
private Object convertIfNecessary(String propertyName, Object oldValue, Object newValue, Class<?> requiredType)
throws TypeMismatchException {
return convertIfNecessary(propertyName, oldValue, newValue, requiredType, TypeDescriptor.valueOf(requiredType));
}
/** /**
* Convert the given value for the specified property to the latter's type. * Convert the given value for the specified property to the latter's type.
* <p>This method is only intended for optimizations in a BeanFactory. * <p>This method is only intended for optimizations in a BeanFactory.
@ -497,7 +491,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
throws TypeMismatchException { throws TypeMismatchException {
return convertIfNecessary(propertyName, oldValue, newValue, pd.getPropertyType(), return convertIfNecessary(propertyName, oldValue, newValue, pd.getPropertyType(),
new PropertyTypeDescriptor(pd, BeanUtils.getWriteMethodParameter(pd))); new PropertyTypeDescriptor(BeanUtils.getWriteMethodParameter(pd), pd));
} }
@ -794,7 +788,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
// IMPORTANT: Do not pass full property name in here - property editors // IMPORTANT: Do not pass full property name in here - property editors
// must not kick in for map keys but rather only for map values. // must not kick in for map keys but rather only for map values.
Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType, Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType,
new PropertyTypeDescriptor(pd, new MethodParameter(pd.getReadMethod(), -1), mapKeyType)); new PropertyTypeDescriptor(mapKeyType, new MethodParameter(pd.getReadMethod(), -1), pd));
value = map.get(convertedMapKey); value = map.get(convertedMapKey);
} }
else { else {
@ -942,7 +936,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
oldValue = Array.get(propValue, arrayIndex); oldValue = Array.get(propValue, arrayIndex);
} }
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), requiredType, Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), requiredType,
new PropertyTypeDescriptor(pd, new MethodParameter(pd.getReadMethod(), -1), requiredType)); new PropertyTypeDescriptor(requiredType, new MethodParameter(pd.getReadMethod(), -1), pd));
Array.set(propValue, arrayIndex, convertedValue); Array.set(propValue, arrayIndex, convertedValue);
} }
catch (IndexOutOfBoundsException ex) { catch (IndexOutOfBoundsException ex) {
@ -961,7 +955,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
oldValue = list.get(index); oldValue = list.get(index);
} }
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), requiredType, Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), requiredType,
new PropertyTypeDescriptor(pd, new MethodParameter(pd.getReadMethod(), -1), requiredType)); new PropertyTypeDescriptor(requiredType, new MethodParameter(pd.getReadMethod(), -1), pd));
if (index < list.size()) { if (index < list.size()) {
list.set(index, convertedValue); list.set(index, convertedValue);
} }
@ -990,7 +984,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
// IMPORTANT: Do not pass full property name in here - property editors // IMPORTANT: Do not pass full property name in here - property editors
// must not kick in for map keys but rather only for map values. // must not kick in for map keys but rather only for map values.
Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType, Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType,
new PropertyTypeDescriptor(pd, new MethodParameter(pd.getReadMethod(), -1), mapKeyType)); new PropertyTypeDescriptor(mapKeyType, new MethodParameter(pd.getReadMethod(), -1), pd));
Object oldValue = null; Object oldValue = null;
if (isExtractOldValueForEditor()) { if (isExtractOldValueForEditor()) {
oldValue = map.get(convertedMapKey); oldValue = map.get(convertedMapKey);

View File

@ -136,7 +136,7 @@ class TypeConverterDelegate {
ConversionService conversionService = this.propertyEditorRegistry.getConversionService(); ConversionService conversionService = this.propertyEditorRegistry.getConversionService();
if (editor == null && conversionService != null && convertedValue != null) { if (editor == null && conversionService != null && convertedValue != null) {
TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(convertedValue); TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(convertedValue);
TypeDescriptor targetTypeDesc = typeDescriptor.forElementType(requiredType); TypeDescriptor targetTypeDesc = typeDescriptor;
if (conversionService.canConvert(sourceTypeDesc, targetTypeDesc)) { if (conversionService.canConvert(sourceTypeDesc, targetTypeDesc)) {
return (T) conversionService.convert(convertedValue, sourceTypeDesc, targetTypeDesc); return (T) conversionService.convert(convertedValue, sourceTypeDesc, targetTypeDesc);
} }

View File

@ -1,39 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<classpath> <classpath>
<classpathentry kind="src" path="src/main/java"/> <classpathentry kind="src" path="src/main/java"/>
<classpathentry kind="src" path="src/main/resources"/> <classpathentry kind="src" path="src/main/resources"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/> <classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/resources"/> <classpathentry kind="src" output="target/test-classes" path="src/test/resources"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry combineaccessrules="false" kind="src" path="/org.springframework.aop"/> <classpathentry combineaccessrules="false" kind="src" path="/org.springframework.aop"/>
<classpathentry combineaccessrules="false" kind="src" path="/org.springframework.beans"/> <classpathentry combineaccessrules="false" kind="src" path="/org.springframework.beans"/>
<classpathentry combineaccessrules="false" kind="src" path="/org.springframework.core"/> <classpathentry combineaccessrules="false" kind="src" path="/org.springframework.core"/>
<classpathentry combineaccessrules="false" kind="src" path="/org.springframework.expression"/> <classpathentry combineaccessrules="false" kind="src" path="/org.springframework.expression"/>
<classpathentry combineaccessrules="false" kind="src" path="/org.springframework.instrument"/> <classpathentry combineaccessrules="false" kind="src" path="/org.springframework.instrument"/>
<classpathentry kind="lib" path="/org.springframework.asm/target/artifacts/org.springframework.asm.jar" sourcepath="/org.springframework.asm/target/artifacts/org.springframework.asm-sources.jar"/> <classpathentry kind="lib" path="/org.springframework.asm/target/artifacts/org.springframework.asm.jar" sourcepath="/org.springframework.asm/target/artifacts/org.springframework.asm-sources.jar"/>
<classpathentry kind="var" path="IVY_CACHE/edu.emory.mathcs.backport/com.springsource.edu.emory.mathcs.backport/3.0.0/com.springsource.edu.emory.mathcs.backport-3.0.0.jar" sourcepath="/IVY_CACHE/edu.emory.mathcs.backport/com.springsource.edu.emory.mathcs.backport/3.0.0/com.springsource.edu.emory.mathcs.backport-sources-3.0.0.jar"/> <classpathentry kind="var" path="IVY_CACHE/edu.emory.mathcs.backport/com.springsource.edu.emory.mathcs.backport/3.0.0/com.springsource.edu.emory.mathcs.backport-3.0.0.jar" sourcepath="/IVY_CACHE/edu.emory.mathcs.backport/com.springsource.edu.emory.mathcs.backport/3.0.0/com.springsource.edu.emory.mathcs.backport-sources-3.0.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/javax.ejb/com.springsource.javax.ejb/3.0.0/com.springsource.javax.ejb-3.0.0.jar" sourcepath="/IVY_CACHE/javax.ejb/com.springsource.javax.ejb/3.0.0/com.springsource.javax.ejb-sources-3.0.0.jar"/> <classpathentry kind="var" path="IVY_CACHE/javax.ejb/com.springsource.javax.ejb/3.0.0/com.springsource.javax.ejb-3.0.0.jar" sourcepath="/IVY_CACHE/javax.ejb/com.springsource.javax.ejb/3.0.0/com.springsource.javax.ejb-sources-3.0.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/javax.inject/com.springsource.javax.inject/1.0.0/com.springsource.javax.inject-1.0.0.jar" sourcepath="/IVY_CACHE/javax.inject/com.springsource.javax.inject/1.0.0/com.springsource.javax.inject-sources-1.0.0.jar"/> <classpathentry kind="var" path="IVY_CACHE/javax.inject/com.springsource.javax.inject/1.0.0/com.springsource.javax.inject-1.0.0.jar" sourcepath="/IVY_CACHE/javax.inject/com.springsource.javax.inject/1.0.0/com.springsource.javax.inject-sources-1.0.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/javax.jms/com.springsource.javax.jms/1.1.0/com.springsource.javax.jms-1.1.0.jar" sourcepath="/IVY_CACHE/javax.jms/com.springsource.javax.jms/1.1.0/com.springsource.javax.jms-sources-1.1.0.jar"/> <classpathentry kind="var" path="IVY_CACHE/javax.jms/com.springsource.javax.jms/1.1.0/com.springsource.javax.jms-1.1.0.jar" sourcepath="/IVY_CACHE/javax.jms/com.springsource.javax.jms/1.1.0/com.springsource.javax.jms-sources-1.1.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/javax.persistence/com.springsource.javax.persistence/1.0.0/com.springsource.javax.persistence-1.0.0.jar" sourcepath="/IVY_CACHE/javax.persistence/com.springsource.javax.persistence/1.0.0/com.springsource.javax.persistence-sources-1.0.0.jar"/> <classpathentry kind="var" path="IVY_CACHE/javax.persistence/com.springsource.javax.persistence/1.0.0/com.springsource.javax.persistence-1.0.0.jar" sourcepath="/IVY_CACHE/javax.persistence/com.springsource.javax.persistence/1.0.0/com.springsource.javax.persistence-sources-1.0.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/javax.transaction/com.springsource.javax.transaction/1.1.0/com.springsource.javax.transaction-1.1.0.jar" sourcepath="/IVY_CACHE/javax.transaction/com.springsource.javax.transaction/1.1.0/com.springsource.javax.transaction-sources-1.1.0.jar"/> <classpathentry kind="var" path="IVY_CACHE/javax.transaction/com.springsource.javax.transaction/1.1.0/com.springsource.javax.transaction-1.1.0.jar" sourcepath="/IVY_CACHE/javax.transaction/com.springsource.javax.transaction/1.1.0/com.springsource.javax.transaction-sources-1.1.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/javax.validation/com.springsource.javax.validation/1.0.0.GA/com.springsource.javax.validation-1.0.0.GA.jar" sourcepath="/IVY_CACHE/javax.validation/com.springsource.javax.validation/1.0.0/com.springsource.javax.validation-sources-1.0.0.GA.jar"/> <classpathentry kind="var" path="IVY_CACHE/javax.validation/com.springsource.javax.validation/1.0.0.GA/com.springsource.javax.validation-1.0.0.GA.jar" sourcepath="/IVY_CACHE/javax.validation/com.springsource.javax.validation/1.0.0/com.springsource.javax.validation-sources-1.0.0.GA.jar"/>
<classpathentry kind="var" path="IVY_CACHE/javax.xml.rpc/com.springsource.javax.xml.rpc/1.1.0/com.springsource.javax.xml.rpc-1.1.0.jar"/> <classpathentry kind="var" path="IVY_CACHE/javax.xml.rpc/com.springsource.javax.xml.rpc/1.1.0/com.springsource.javax.xml.rpc-1.1.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/net.sourceforge.cglib/com.springsource.net.sf.cglib/2.2.0/com.springsource.net.sf.cglib-2.2.0.jar" sourcepath="/IVY_CACHE/net.sourceforge.cglib/com.springsource.net.sf.cglib/2.1.3/com.springsource.net.sf.cglib-sources-2.1.3.jar"/> <classpathentry kind="var" path="IVY_CACHE/net.sourceforge.cglib/com.springsource.net.sf.cglib/2.2.0/com.springsource.net.sf.cglib-2.2.0.jar" sourcepath="/IVY_CACHE/net.sourceforge.cglib/com.springsource.net.sf.cglib/2.1.3/com.springsource.net.sf.cglib-sources-2.1.3.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.aopalliance/com.springsource.org.aopalliance/1.0.0/com.springsource.org.aopalliance-1.0.0.jar" sourcepath="/IVY_CACHE/org.aopalliance/com.springsource.org.aopalliance/1.0.0/com.springsource.org.aopalliance-sources-1.0.0.jar"/> <classpathentry kind="var" path="IVY_CACHE/org.aopalliance/com.springsource.org.aopalliance/1.0.0/com.springsource.org.aopalliance-1.0.0.jar" sourcepath="/IVY_CACHE/org.aopalliance/com.springsource.org.aopalliance/1.0.0/com.springsource.org.aopalliance-sources-1.0.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.dbcp/1.2.2.osgi/com.springsource.org.apache.commons.dbcp-1.2.2.osgi.jar" sourcepath="/IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.dbcp/1.2.2.osgi/com.springsource.org.apache.commons.dbcp-sources-1.2.2.osgi.jar"/> <classpathentry kind="var" path="IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.dbcp/1.2.2.osgi/com.springsource.org.apache.commons.dbcp-1.2.2.osgi.jar" sourcepath="/IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.dbcp/1.2.2.osgi/com.springsource.org.apache.commons.dbcp-sources-1.2.2.osgi.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-1.1.1.jar" sourcepath="/IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-sources-1.1.1.jar"/> <classpathentry kind="var" path="IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-1.1.1.jar" sourcepath="/IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-sources-1.1.1.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.pool/1.5.3/com.springsource.org.apache.commons.pool-1.5.3.jar" sourcepath="/IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.pool/1.5.3/com.springsource.org.apache.commons.pool-sources-1.5.3.jar"/> <classpathentry kind="var" path="IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.pool/1.5.3/com.springsource.org.apache.commons.pool-1.5.3.jar" sourcepath="/IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.pool/1.5.3/com.springsource.org.apache.commons.pool-sources-1.5.3.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.apache.log4j/com.springsource.org.apache.log4j/1.2.15/com.springsource.org.apache.log4j-1.2.15.jar" sourcepath="/IVY_CACHE/org.apache.log4j/com.springsource.org.apache.log4j/1.2.15/com.springsource.org.apache.log4j-sources-1.2.15.jar"/> <classpathentry kind="var" path="IVY_CACHE/org.apache.log4j/com.springsource.org.apache.log4j/1.2.15/com.springsource.org.apache.log4j-1.2.15.jar" sourcepath="/IVY_CACHE/org.apache.log4j/com.springsource.org.apache.log4j/1.2.15/com.springsource.org.apache.log4j-sources-1.2.15.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.aspectj/com.springsource.org.aspectj.weaver/1.6.8.RELEASE/com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar"/> <classpathentry kind="var" path="IVY_CACHE/org.aspectj/com.springsource.org.aspectj.weaver/1.6.8.RELEASE/com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.beanshell/com.springsource.bsh/2.0.0.b4/com.springsource.bsh-2.0.0.b4.jar"/> <classpathentry kind="var" path="IVY_CACHE/org.beanshell/com.springsource.bsh/2.0.0.b4/com.springsource.bsh-2.0.0.b4.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.codehaus.groovy/com.springsource.org.codehaus.groovy/1.6.5/com.springsource.org.codehaus.groovy-1.6.5.jar" sourcepath="/IVY_CACHE/org.codehaus.groovy/com.springsource.org.codehaus.groovy/1.6.5/com.springsource.org.codehaus.groovy-sources-1.6.5.jar"/> <classpathentry kind="var" path="IVY_CACHE/org.codehaus.groovy/com.springsource.org.codehaus.groovy/1.6.5/com.springsource.org.codehaus.groovy-1.6.5.jar" sourcepath="/IVY_CACHE/org.codehaus.groovy/com.springsource.org.codehaus.groovy/1.6.5/com.springsource.org.codehaus.groovy-sources-1.6.5.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.hamcrest/com.springsource.org.hamcrest/1.1.0/com.springsource.org.hamcrest-1.1.0.jar" sourcepath="/IVY_CACHE/org.hamcrest/1.1.0/com.springsource.org.hamcrest-1.1.0.jar"/> <classpathentry kind="var" path="IVY_CACHE/org.hamcrest/com.springsource.org.hamcrest/1.1.0/com.springsource.org.hamcrest-1.1.0.jar" sourcepath="/IVY_CACHE/org.hamcrest/1.1.0/com.springsource.org.hamcrest-1.1.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.easymock/com.springsource.org.easymock/2.5.1/com.springsource.org.easymock-2.5.1.jar" sourcepath="/IVY_CACHE/org.easymock/com.springsource.org.easymock/2.5.1/com.springsource.org.easymock-sources-2.5.1.jar"/> <classpathentry kind="var" path="IVY_CACHE/org.easymock/com.springsource.org.easymock/2.5.1/com.springsource.org.easymock-2.5.1.jar" sourcepath="/IVY_CACHE/org.easymock/com.springsource.org.easymock/2.5.1/com.springsource.org.easymock-sources-2.5.1.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.joda/com.springsource.org.joda.time/1.6.0/com.springsource.org.joda.time-1.6.0.jar" sourcepath="/IVY_CACHE/org.joda/com.springsource.org.joda.time/1.6.0/com.springsource.org.joda.time-sources-1.6.0.jar"/> <classpathentry kind="var" path="IVY_CACHE/org.joda/com.springsource.org.joda.time/1.6.0/com.springsource.org.joda.time-1.6.0.jar" sourcepath="/IVY_CACHE/org.joda/com.springsource.org.joda.time/1.6.0/com.springsource.org.joda.time-sources-1.6.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.jruby/com.springsource.org.jruby/1.4.0/com.springsource.org.jruby-1.4.0.jar" sourcepath="/IVY_CACHE/org.jruby/com.springsource.org.jruby/1.4.0/com.springsource.org.jruby-sources-1.4.0.jar"/> <classpathentry kind="var" path="IVY_CACHE/org.jruby/com.springsource.org.jruby/1.4.0/com.springsource.org.jruby-1.4.0.jar" sourcepath="/IVY_CACHE/org.jruby/com.springsource.org.jruby/1.4.0/com.springsource.org.jruby-sources-1.4.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.junit/com.springsource.org.junit/4.8.1/com.springsource.org.junit-4.8.1.jar" sourcepath="/IVY_CACHE/org.junit/com.springsource.org.junit/4.8.1/com.springsource.org.junit-sources-4.8.1.jar"/> <classpathentry kind="var" path="IVY_CACHE/org.junit/com.springsource.org.junit/4.8.1/com.springsource.org.junit-4.8.1.jar" sourcepath="/IVY_CACHE/org.junit/com.springsource.org.junit/4.8.1/com.springsource.org.junit-sources-4.8.1.jar"/>
<classpathentry kind="var" path="IVY_CACHE/javax.inject/com.springsource.org.atinject.tck/1.0.0/com.springsource.org.atinject.tck-1.0.0.jar" sourcepath="/IVY_CACHE/javax.inject/com.springsource.org.atinject.tck/1.0.0/com.springsource.org.atinject.tck-sources-1.0.0.jar"/> <classpathentry kind="var" path="IVY_CACHE/javax.inject/com.springsource.org.atinject.tck/1.0.0/com.springsource.org.atinject.tck-1.0.0.jar" sourcepath="/IVY_CACHE/javax.inject/com.springsource.org.atinject.tck/1.0.0/com.springsource.org.atinject.tck-sources-1.0.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.hibernate/com.springsource.org.hibernate.validator/4.1.0.GA/com.springsource.org.hibernate.validator-4.1.0.GA.jar"/> <classpathentry kind="var" path="IVY_CACHE/org.hibernate/com.springsource.org.hibernate.validator/4.1.0.GA/com.springsource.org.hibernate.validator-4.1.0.GA.jar"/>
<classpathentry kind="output" path="target/classes"/> <classpathentry kind="var" path="IVY_CACHE/org.slf4j/com.springsource.slf4j.api/1.5.6/com.springsource.slf4j.api-1.5.6.jar"/>
</classpath> <classpathentry kind="var" path="IVY_CACHE/org.slf4j/com.springsource.slf4j.jcl/1.5.6/com.springsource.slf4j.jcl-1.5.6.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.objectweb.asm/com.springsource.org.objectweb.asm/3.2.0/com.springsource.org.objectweb.asm-3.2.0.jar"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View File

@ -42,9 +42,6 @@ public class TypeDescriptor {
/** Constant defining a TypeDescriptor for a <code>null</code> value */ /** Constant defining a TypeDescriptor for a <code>null</code> value */
public static final TypeDescriptor NULL = new TypeDescriptor(); public static final TypeDescriptor NULL = new TypeDescriptor();
/** Constant defining a TypeDescriptor for 'unknown type' */
private static final TypeDescriptor UNKNOWN = new TypeDescriptor(Object.class);
private static final Map<Class<?>, TypeDescriptor> typeDescriptorCache = new HashMap<Class<?>, TypeDescriptor>(); private static final Map<Class<?>, TypeDescriptor> typeDescriptorCache = new HashMap<Class<?>, TypeDescriptor>();
private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0]; private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
@ -78,8 +75,6 @@ public class TypeDescriptor {
private int fieldNestingLevel = 1; private int fieldNestingLevel = 1;
private Object value;
private TypeDescriptor elementType; private TypeDescriptor elementType;
private TypeDescriptor mapKeyType; private TypeDescriptor mapKeyType;
@ -97,6 +92,7 @@ public class TypeDescriptor {
*/ */
public TypeDescriptor(MethodParameter methodParameter) { public TypeDescriptor(MethodParameter methodParameter) {
Assert.notNull(methodParameter, "MethodParameter must not be null"); Assert.notNull(methodParameter, "MethodParameter must not be null");
this.type = methodParameter.getParameterType();
this.methodParameter = methodParameter; this.methodParameter = methodParameter;
} }
@ -107,112 +103,49 @@ public class TypeDescriptor {
*/ */
public TypeDescriptor(Field field) { public TypeDescriptor(Field field) {
Assert.notNull(field, "Field must not be null"); Assert.notNull(field, "Field must not be null");
this.type = field.getType();
this.field = field; this.field = field;
} }
/** /**
* Create a new type descriptor from a method or constructor parameter. * Create a new type descriptor for the given class.
* <p>Use this constructor when a target conversion point originates from a method parameter, * @param type the class
* such as a setter method argument. * @return the type descriptor
* @param methodParameter the MethodParameter to wrap
* @param type the specific type to expose (may be an array/collection element)
*/ */
public TypeDescriptor(MethodParameter methodParameter, Class<?> type) { public static TypeDescriptor valueOf(Class<?> type) {
Assert.notNull(methodParameter, "MethodParameter must not be null"); if (type == null) {
this.methodParameter = methodParameter; return NULL;
this.type = type; }
TypeDescriptor desc = typeDescriptorCache.get(type);
return (desc != null ? desc : new TypeDescriptor(type));
} }
/** /**
* Create a new type descriptor for a field. * Create a new type descriptor for the class of the given object.
* Use this constructor when a target conversion point originates from a field. * @param object the object
* @param field the field to wrap * @return the type descriptor
* @param type the specific type to expose (may be an array/collection element)
*/ */
public TypeDescriptor(Field field, Class<?> type) { public static TypeDescriptor forObject(Object object) {
Assert.notNull(field, "Field must not be null"); if (object == null) {
this.field = field; return NULL;
this.type = type; }
if (object instanceof Collection<?>) {
return new TypeDescriptor(object.getClass(), CollectionUtils.findCommonElementType((Collection<?>) object));
}
else if (object instanceof Map<?, ?>) {
return new TypeDescriptor(object.getClass(), CollectionUtils.findCommonElementType(((Map<?, ?>) object).keySet()), CollectionUtils.findCommonElementType(((Map<?, ?>) object).values()));
}
else {
return valueOf(object.getClass());
}
} }
/**
* Create a new type descriptor for a field.
* Use this constructor when a target conversion point originates from a field.
* @param field the field to wrap
* @param type the specific type to expose (may be an array/collection element)
*/
private TypeDescriptor(Field field, int nestingLevel, Class<?> type) {
Assert.notNull(field, "Field must not be null");
this.field = field;
this.fieldNestingLevel = nestingLevel;
this.type = type;
}
/**
* Internal constructor for a NULL descriptor.
*/
private TypeDescriptor() {
}
/**
* Create a new descriptor for the type of the given value.
* <p>Use this constructor when a conversion point comes from a source such as a Map or
* Collection, where no additional context is available but elements can be introspected.
* @param value the value to determine the actual type from
*/
private TypeDescriptor(Object value) {
Assert.notNull(value, "Value must not be null");
this.value = value;
this.type = value.getClass();
}
/**
* Create a new descriptor for the given type.
* <p>Use this constructor when a conversion point comes from a plain source type,
* where no additional context is available.
* @param type the actual type to wrap
*/
private TypeDescriptor(Class<?> type) {
Assert.notNull(type, "Type must not be null");
this.type = type;
}
/**
* Return the wrapped MethodParameter, if any.
* <p>Note: Either MethodParameter or Field is available.
* @return the MethodParameter, or <code>null</code> if none
*/
public MethodParameter getMethodParameter() {
return this.methodParameter;
}
/**
* Return the wrapped Field, if any.
* <p>Note: Either MethodParameter or Field is available.
* @return the Field, or <code>null</code> if none
*/
public Field getField() {
return this.field;
}
/** /**
* Determine the declared (non-generic) type of the wrapped parameter/field. * Determine the declared (non-generic) type of the wrapped parameter/field.
* @return the declared type, or <code>null</code> if this is {@link TypeDescriptor#NULL} * @return the declared type, or <code>null</code> if this is {@link TypeDescriptor#NULL}
*/ */
public Class<?> getType() { public Class<?> getType() {
if (this.type != null) { return type;
return this.type;
}
else if (this.field != null) {
return this.field.getType();
}
else if (this.methodParameter != null) {
return this.methodParameter.getParameterType();
}
else {
return null;
}
} }
/** /**
@ -220,140 +153,21 @@ public class TypeDescriptor {
* Returns the Object wrapper type if the underlying type is a primitive. * Returns the Object wrapper type if the underlying type is a primitive.
*/ */
public Class<?> getObjectType() { public Class<?> getObjectType() {
Class<?> type = getType(); return ClassUtils.resolvePrimitiveIfNecessary(getType());
return (type != null ? ClassUtils.resolvePrimitiveIfNecessary(type) : type);
} }
/** /**
* Returns the name of this type: the fully qualified class name. * Returns the name of this type: the fully qualified class name.
*/ */
public String getName() { public String getName() {
Class<?> type = getType(); return ClassUtils.getQualifiedName(getType());
return (type != null ? ClassUtils.getQualifiedName(type) : null);
} }
/** /**
* Is this type a primitive type? * Is this type a primitive type?
*/ */
public boolean isPrimitive() { public boolean isPrimitive() {
Class<?> type = getType(); return getType().isPrimitive();
return (type != null && type.isPrimitive());
}
/**
* Is this type an array type?
*/
public boolean isArray() {
Class<?> type = getType();
return (type != null && type.isArray());
}
/**
* Is this type a {@link Collection} type?
*/
public boolean isCollection() {
return Collection.class.isAssignableFrom(getType());
}
/**
* If this type is an array type or {@link Collection} type, returns the underlying element type.
* Returns <code>null</code> if the type is neither an array or collection.
*/
public Class<?> getElementType() {
return getElementTypeDescriptor().getType();
}
/**
* Return the element type as a type descriptor.
*/
public synchronized TypeDescriptor getElementTypeDescriptor() {
if (this.elementType == null) {
this.elementType = forElementType(resolveElementType());
}
return this.elementType;
}
/**
* Return the element type as a type descriptor. If the element type is null
* (cannot be determined), the type descriptor is derived from the element argument.
* @param element the element
* @return the element type descriptor
*/
public TypeDescriptor getElementTypeDescriptor(Object element) {
TypeDescriptor elementType = getElementTypeDescriptor();
return (elementType != TypeDescriptor.UNKNOWN ? elementType : forObject(element));
}
/**
* Is this type a {@link Map} type?
*/
public boolean isMap() {
return Map.class.isAssignableFrom(getType());
}
/**
* Is this descriptor for a map where the key type and value type are known?
*/
public boolean isMapEntryTypeKnown() {
return (isMap() && getMapKeyType() != null && getMapValueType() != null);
}
/**
* Determine the generic key type of the wrapped Map parameter/field, if any.
* @return the generic type, or <code>null</code> if none
*/
public Class<?> getMapKeyType() {
return getMapKeyTypeDescriptor().getType();
}
/**
* Returns map key type as a type descriptor.
*/
public synchronized TypeDescriptor getMapKeyTypeDescriptor() {
if (this.mapKeyType == null) {
this.mapKeyType = forElementType(resolveMapKeyType());
}
return this.mapKeyType;
}
/**
* Return the map key type as a type descriptor. If the key type is null
* (cannot be determined), the type descriptor is derived from the key argument.
* @param key the key
* @return the map key type descriptor
*/
public TypeDescriptor getMapKeyTypeDescriptor(Object key) {
TypeDescriptor keyType = getMapKeyTypeDescriptor();
return (keyType != TypeDescriptor.UNKNOWN ? keyType : TypeDescriptor.forObject(key));
}
/**
* Determine the generic value type of the wrapped Map parameter/field, if any.
* @return the generic type, or <code>null</code> if none
*/
public Class<?> getMapValueType() {
return getMapValueTypeDescriptor().getType();
}
/**
* Returns map value type as a type descriptor.
*/
public synchronized TypeDescriptor getMapValueTypeDescriptor() {
if (this.mapValueType == null) {
this.mapValueType = forElementType(resolveMapValueType());
}
return this.mapValueType;
}
/**
* Return the map value type as a type descriptor. If the value type is null
* (cannot be determined), the type descriptor is derived from the value argument.
* @param value the value
* @return the map value type descriptor
*/
public TypeDescriptor getMapValueTypeDescriptor(Object value) {
TypeDescriptor valueType = getMapValueTypeDescriptor();
return (valueType != TypeDescriptor.UNKNOWN ? valueType : TypeDescriptor.forObject(value));
} }
/** /**
@ -402,28 +216,130 @@ public class TypeDescriptor {
} }
/** /**
* Create a copy of this type descriptor, preserving the context information * A textual representation of the type descriptor (eg. Map<String,Foo>) for use in messages.
* but exposing the specified element type (e.g. an array/collection/map element).
* @param elementType the desired type to expose
* @return the type descriptor
*/ */
public TypeDescriptor forElementType(Class<?> elementType) { public String asString() {
if (elementType == null) { return toString();
return TypeDescriptor.UNKNOWN; }
}
else if (this.methodParameter != null) { // indexable type descriptor operations
MethodParameter nested = new MethodParameter(this.methodParameter);
nested.increaseNestingLevel(); /**
return new TypeDescriptor(nested, elementType); * Is this type an array type?
} */
else if (this.field != null) { public boolean isArray() {
return new TypeDescriptor(this.field, this.fieldNestingLevel + 1, elementType); return getType().isArray();
}
else {
return TypeDescriptor.valueOf(elementType);
}
} }
/**
* Is this type a {@link Collection} type?
*/
public boolean isCollection() {
return Collection.class.isAssignableFrom(getType());
}
/**
* If this type is an array type or {@link Collection} type, returns the underlying element type.
* Returns <code>null</code> if the type is neither an array or collection.
*/
public Class<?> getElementType() {
return getElementTypeDescriptor().getType();
}
/**
* Return the element type as a type descriptor.
*/
public synchronized TypeDescriptor getElementTypeDescriptor() {
if (!isCollection() && !isArray()) {
throw new IllegalStateException("Not a collection or array type");
}
if (this.elementType == null) {
this.elementType = resolveElementTypeDescriptor();
}
return this.elementType;
}
// map type descriptor operations
/**
* Is this type a {@link Map} type?
*/
public boolean isMap() {
return Map.class.isAssignableFrom(getType());
}
/**
* Determine the generic key type of the wrapped Map parameter/field, if any.
* @return the generic type, or <code>null</code> if none
*/
public Class<?> getMapKeyType() {
return getMapKeyTypeDescriptor().getType();
}
/**
* Returns map key type as a type descriptor.
*/
public synchronized TypeDescriptor getMapKeyTypeDescriptor() {
if (!isMap()) {
throw new IllegalStateException("Not a Map type");
}
if (this.mapKeyType == null) {
this.mapKeyType = resolveMapKeyTypeDescriptor();
}
return this.mapKeyType;
}
/**
* Determine the generic value type of the wrapped Map parameter/field, if any.
* @return the generic type, or <code>null</code> if none
*/
public Class<?> getMapValueType() {
return getMapValueTypeDescriptor().getType();
}
/**
* Returns map value type as a type descriptor.
*/
public synchronized TypeDescriptor getMapValueTypeDescriptor() {
if (this.mapValueType == null) {
this.mapValueType = resolveMapValueTypeDescriptor();
}
return this.mapValueType;
}
// special case public operations
public TypeDescriptor(Class<?> componentType, MethodParameter methodParameter) {
if (componentType == null) {
componentType = Object.class;
}
this.type = componentType;
this.methodParameter = methodParameter;
}
public MethodParameter getMethodParameter() {
return methodParameter;
}
public TypeDescriptor applyType(Object object) {
if (object == null) {
return this;
}
// TODO preserve binding context with returned copy
// TODO fall back to generic info if collection is empty
if (object instanceof Collection<?>) {
return new TypeDescriptor(object.getClass(), CollectionUtils.findCommonElementType((Collection<?>) object));
}
else if (object instanceof Map<?, ?>) {
return new TypeDescriptor(object.getClass(), CollectionUtils.findCommonElementType(((Map<?, ?>) object).keySet()), CollectionUtils.findCommonElementType(((Map<?, ?>) object).values()));
}
else {
return valueOf(object.getClass());
}
}
// extending Object
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (this == obj) { if (this == obj) {
return true; return true;
@ -432,8 +348,7 @@ public class TypeDescriptor {
return false; return false;
} }
TypeDescriptor other = (TypeDescriptor) obj; TypeDescriptor other = (TypeDescriptor) obj;
boolean annotatedTypeEquals = boolean annotatedTypeEquals = getType().equals(other.getType()) && ObjectUtils.nullSafeEquals(getAnnotations(), other.getAnnotations());
getType().equals(other.getType()) && ObjectUtils.nullSafeEquals(getAnnotations(), other.getAnnotations());
if (isCollection()) { if (isCollection()) {
return annotatedTypeEquals && ObjectUtils.nullSafeEquals(getElementType(), other.getElementType()); return annotatedTypeEquals && ObjectUtils.nullSafeEquals(getElementType(), other.getElementType());
} }
@ -450,13 +365,6 @@ public class TypeDescriptor {
return (this == TypeDescriptor.NULL ? 0 : getType().hashCode()); return (this == TypeDescriptor.NULL ? 0 : getType().hashCode());
} }
/**
* A textual representation of the type descriptor (eg. Map<String,Foo>) for use in messages.
*/
public String asString() {
return toString();
}
public String toString() { public String toString() {
if (this == TypeDescriptor.NULL) { if (this == TypeDescriptor.NULL) {
return "null"; return "null";
@ -479,82 +387,9 @@ public class TypeDescriptor {
} }
} }
// subclassing hooks
// internal helpers
protected Annotation[] resolveAnnotations() {
private Class<?> resolveElementType() {
if (isArray()) {
return getType().getComponentType();
}
else if (isCollection()) {
return resolveCollectionElementType();
}
else {
return null;
}
}
@SuppressWarnings("unchecked")
private Class<?> resolveCollectionElementType() {
if (this.field != null) {
return GenericCollectionTypeResolver.getCollectionFieldType(this.field, this.fieldNestingLevel);
}
else if (this.methodParameter != null) {
return GenericCollectionTypeResolver.getCollectionParameterType(this.methodParameter);
}
else if (this.value instanceof Collection) {
Class<?> elementType = CollectionUtils.findCommonElementType((Collection) this.value);
if (elementType != null) {
return elementType;
}
}
else if (this.type != null) {
return GenericCollectionTypeResolver.getCollectionType((Class<? extends Collection>) this.type);
}
return null;
}
@SuppressWarnings("unchecked")
private Class<?> resolveMapKeyType() {
if (this.field != null) {
return GenericCollectionTypeResolver.getMapKeyFieldType(this.field);
}
else if (this.methodParameter != null) {
return GenericCollectionTypeResolver.getMapKeyParameterType(this.methodParameter);
}
else if (this.value instanceof Map<?, ?>) {
Class<?> keyType = CollectionUtils.findCommonElementType(((Map<?, ?>) this.value).keySet());
if (keyType != null) {
return keyType;
}
}
else if (this.type != null && isMap()) {
return GenericCollectionTypeResolver.getMapKeyType((Class<? extends Map>) this.type);
}
return null;
}
@SuppressWarnings("unchecked")
private Class<?> resolveMapValueType() {
if (this.field != null) {
return GenericCollectionTypeResolver.getMapValueFieldType(this.field);
}
else if (this.methodParameter != null) {
return GenericCollectionTypeResolver.getMapValueParameterType(this.methodParameter);
}
else if (this.value instanceof Map<?, ?>) {
Class<?> valueType = CollectionUtils.findCommonElementType(((Map<?, ?>) this.value).values());
if (valueType != null) {
return valueType;
}
}
else if (this.type != null && isMap()) {
return GenericCollectionTypeResolver.getMapValueType((Class<? extends Map>) this.type);
}
return null;
}
private Annotation[] resolveAnnotations() {
if (this.field != null) { if (this.field != null) {
return this.field.getAnnotations(); return this.field.getAnnotations();
} }
@ -571,37 +406,118 @@ public class TypeDescriptor {
} }
} }
protected TypeDescriptor newComponentTypeDescriptor(Class<?> componentType, MethodParameter nested) {
return new TypeDescriptor(componentType, nested);
}
// internal helpers
// static factory methods private TypeDescriptor resolveElementTypeDescriptor() {
if (isCollection()) {
/** return createComponentTypeDescriptor(resolveCollectionElementType());
* Create a new type descriptor for the class of the given object.
* @param object the object
* @return the type descriptor
*/
public static TypeDescriptor forObject(Object object) {
if (object == null) {
return NULL;
}
else if (object instanceof Collection<?> || object instanceof Map<?, ?>) {
return new TypeDescriptor(object);
} }
else { else {
return valueOf(object.getClass()); // TODO: GenericCollectionTypeResolver is not capable of applying nesting levels to array fields;
// this means generic info of nested lists or maps stored inside array method parameters or fields is not obtainable
return createComponentTypeDescriptor(getType().getComponentType());
} }
} }
/** private TypeDescriptor resolveMapKeyTypeDescriptor() {
* Create a new type descriptor for the given class. return createComponentTypeDescriptor(resolveMapKeyType());
* @param type the class
* @return the type descriptor
*/
public static TypeDescriptor valueOf(Class<?> type) {
if (type == null) {
return TypeDescriptor.NULL;
}
TypeDescriptor desc = typeDescriptorCache.get(type);
return (desc != null ? desc : new TypeDescriptor(type));
} }
} private TypeDescriptor resolveMapValueTypeDescriptor() {
return createComponentTypeDescriptor(resolveMapValueType());
}
private TypeDescriptor createComponentTypeDescriptor(Class<?> componentType) {
if (componentType == null) {
componentType = Object.class;
}
if (this.methodParameter != null) {
MethodParameter nested = new MethodParameter(this.methodParameter);
nested.increaseNestingLevel();
return newComponentTypeDescriptor(componentType, nested);
}
else if (this.field != null) {
return new TypeDescriptor(componentType, this.field, this.fieldNestingLevel + 1);
}
else {
return TypeDescriptor.valueOf(componentType);
}
}
private Class<?> resolveCollectionElementType() {
if (this.methodParameter != null) {
return GenericCollectionTypeResolver.getCollectionParameterType(this.methodParameter);
}
else if (this.field != null) {
return GenericCollectionTypeResolver.getCollectionFieldType(this.field, this.fieldNestingLevel);
}
else {
return GenericCollectionTypeResolver.getCollectionType((Class<? extends Collection>) this.type);
}
}
private Class<?> resolveMapKeyType() {
if (this.methodParameter != null) {
return GenericCollectionTypeResolver.getMapKeyParameterType(this.methodParameter);
}
else if (this.field != null) {
return GenericCollectionTypeResolver.getMapKeyFieldType(this.field, this.fieldNestingLevel);
}
else {
return GenericCollectionTypeResolver.getMapKeyType((Class<? extends Map>) this.type);
}
}
private Class<?> resolveMapValueType() {
if (this.methodParameter != null) {
return GenericCollectionTypeResolver.getMapValueParameterType(this.methodParameter);
}
else if (this.field != null) {
return GenericCollectionTypeResolver.getMapValueFieldType(this.field, this.fieldNestingLevel);
}
else {
return GenericCollectionTypeResolver.getMapValueType((Class<? extends Map>) this.type);
}
}
// internal constructors
private TypeDescriptor(Class<?> componentType, Field field, int nestingLevel) {
this.type = componentType;
this.field = field;
this.fieldNestingLevel = nestingLevel;
}
private TypeDescriptor() {
}
private TypeDescriptor(Class<?> type) {
Assert.notNull(type, "Type must not be null");
this.type = type;
}
private TypeDescriptor(Class<?> collectionType, Class<?> elementType) {
this.type = collectionType;
if (elementType == null) {
elementType = Object.class;
}
this.elementType = TypeDescriptor.valueOf(elementType);
}
private TypeDescriptor(Class<?> mapType, Class<?> keyType, Class<?> valueType) {
this.type = mapType;
if (keyType == null) {
keyType = Object.class;
}
if (valueType == null) {
valueType = Object.class;
}
this.mapKeyType = TypeDescriptor.valueOf(keyType);
this.mapValueType = TypeDescriptor.valueOf(valueType);
}
}

View File

@ -52,7 +52,6 @@ final class ArrayToCollectionConverter implements ConditionalGenericConverter {
return this.conversionService.canConvert(sourceType.getElementTypeDescriptor(), targetType.getElementTypeDescriptor()); return this.conversionService.canConvert(sourceType.getElementTypeDescriptor(), targetType.getElementTypeDescriptor());
} }
@SuppressWarnings("unchecked")
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (source == null) { if (source == null) {
return null; return null;
@ -61,7 +60,7 @@ final class ArrayToCollectionConverter implements ConditionalGenericConverter {
Collection target = CollectionFactory.createCollection(targetType.getType(), length); Collection target = CollectionFactory.createCollection(targetType.getType(), length);
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
Object sourceElement = Array.get(source, i); Object sourceElement = Array.get(source, i);
Object targetElement = this.conversionService.convert(sourceElement, sourceType.getElementTypeDescriptor(), targetType.getElementTypeDescriptor(sourceElement)); Object targetElement = this.conversionService.convert(sourceElement, sourceType.getElementTypeDescriptor(), targetType.getElementTypeDescriptor());
target.add(targetElement); target.add(targetElement);
} }
return target; return target;

View File

@ -60,7 +60,7 @@ final class CollectionToArrayConverter implements ConditionalGenericConverter {
Object array = Array.newInstance(targetType.getElementType(), sourceCollection.size()); Object array = Array.newInstance(targetType.getElementType(), sourceCollection.size());
int i = 0; int i = 0;
for (Object sourceElement : sourceCollection) { for (Object sourceElement : sourceCollection) {
Object targetElement = this.conversionService.convert(sourceElement, sourceType.getElementTypeDescriptor(sourceElement), targetType.getElementTypeDescriptor()); Object targetElement = this.conversionService.convert(sourceElement, sourceType.getElementTypeDescriptor(), targetType.getElementTypeDescriptor());
Array.set(array, i++, targetElement); Array.set(array, i++, targetElement);
} }
return array; return array;

View File

@ -52,7 +52,6 @@ final class CollectionToCollectionConverter implements ConditionalGenericConvert
return this.conversionService.canConvert(sourceType.getElementTypeDescriptor(), targetType.getElementTypeDescriptor()); return this.conversionService.canConvert(sourceType.getElementTypeDescriptor(), targetType.getElementTypeDescriptor());
} }
@SuppressWarnings("unchecked")
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (source == null) { if (source == null) {
return null; return null;
@ -63,9 +62,7 @@ final class CollectionToCollectionConverter implements ConditionalGenericConvert
} }
Collection target = CollectionFactory.createCollection(targetType.getType(), sourceCollection.size()); Collection target = CollectionFactory.createCollection(targetType.getType(), sourceCollection.size());
for (Object sourceElement : sourceCollection) { for (Object sourceElement : sourceCollection) {
Object targetElement = this.conversionService.convert(sourceElement, Object targetElement = this.conversionService.convert(sourceElement, sourceType.getElementTypeDescriptor(), targetType.getElementTypeDescriptor());
sourceType.getElementTypeDescriptor(sourceElement),
targetType.getElementTypeDescriptor(sourceElement));
target.add(targetElement); target.add(targetElement);
} }
return target; return target;

View File

@ -55,7 +55,7 @@ final class CollectionToObjectConverter implements ConditionalGenericConverter {
return null; return null;
} }
Object firstElement = sourceCollection.iterator().next(); Object firstElement = sourceCollection.iterator().next();
return this.conversionService.convert(firstElement, sourceType.getElementTypeDescriptor(firstElement), targetType); return this.conversionService.convert(firstElement, sourceType.getElementTypeDescriptor(), targetType);
} }
} }

View File

@ -62,8 +62,7 @@ final class CollectionToStringConverter implements ConditionalGenericConverter {
if (i > 0) { if (i > 0) {
string.append(DELIMITER); string.append(DELIMITER);
} }
Object targetElement = this.conversionService.convert( Object targetElement = this.conversionService.convert(sourceElement, sourceType.getElementTypeDescriptor(), targetType);
sourceElement, sourceType.getElementTypeDescriptor(sourceElement), targetType);
string.append(targetElement); string.append(targetElement);
i++; i++;
} }

View File

@ -67,12 +67,8 @@ final class MapToMapConverter implements ConditionalGenericConverter {
Map.Entry sourceMapEntry = (Map.Entry) entry; Map.Entry sourceMapEntry = (Map.Entry) entry;
Object sourceKey = sourceMapEntry.getKey(); Object sourceKey = sourceMapEntry.getKey();
Object sourceValue = sourceMapEntry.getValue(); Object sourceValue = sourceMapEntry.getValue();
Object targetKey = this.conversionService.convert(sourceKey, Object targetKey = this.conversionService.convert(sourceKey, sourceType.getMapKeyTypeDescriptor(), targetType.getMapKeyTypeDescriptor());
sourceType.getMapKeyTypeDescriptor(sourceKey), Object targetValue = this.conversionService.convert(sourceValue, sourceType.getMapValueTypeDescriptor(), targetType.getMapValueTypeDescriptor());
targetType.getMapKeyTypeDescriptor(sourceKey));
Object targetValue = this.conversionService.convert(sourceValue,
sourceType.getMapValueTypeDescriptor(sourceValue),
targetType.getMapValueTypeDescriptor(sourceValue));
targetMap.put(targetKey, targetValue); targetMap.put(targetKey, targetValue);
} }
return targetMap; return targetMap;

View File

@ -49,13 +49,12 @@ final class ObjectToCollectionConverter implements ConditionalGenericConverter {
return this.conversionService.canConvert(sourceType, targetType.getElementTypeDescriptor()); return this.conversionService.canConvert(sourceType, targetType.getElementTypeDescriptor());
} }
@SuppressWarnings("unchecked")
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (source == null) { if (source == null) {
return null; return null;
} }
Collection target = CollectionFactory.createCollection(targetType.getType(), 1); Collection target = CollectionFactory.createCollection(targetType.getType(), 1);
TypeDescriptor elementType = targetType.getElementTypeDescriptor(source); TypeDescriptor elementType = targetType.getElementTypeDescriptor();
// Avoid potential recursion... // Avoid potential recursion...
if (!Collection.class.isAssignableFrom(elementType.getType())) { if (!Collection.class.isAssignableFrom(elementType.getType())) {
target.add(this.conversionService.convert(source, sourceType, elementType)); target.add(this.conversionService.convert(source, sourceType, elementType));

View File

@ -40,31 +40,21 @@ public class PropertyTypeDescriptor extends TypeDescriptor {
private final PropertyDescriptor propertyDescriptor; private final PropertyDescriptor propertyDescriptor;
private Annotation[] cachedAnnotations;
/** /**
* Create a new BeanTypeDescriptor for the given bean property. * Create a new BeanTypeDescriptor for the given bean property.
* @param propertyDescriptor the corresponding JavaBean PropertyDescriptor * @param propertyDescriptor the corresponding JavaBean PropertyDescriptor
* @param methodParameter the target method parameter * @param methodParameter the target method parameter
*/ */
public PropertyTypeDescriptor(PropertyDescriptor propertyDescriptor, MethodParameter methodParameter) { public PropertyTypeDescriptor(MethodParameter methodParameter, PropertyDescriptor propertyDescriptor) {
super(methodParameter); super(methodParameter);
this.propertyDescriptor = propertyDescriptor; this.propertyDescriptor = propertyDescriptor;
} }
/** public PropertyTypeDescriptor(Class<?> componentType, MethodParameter methodParameter, PropertyDescriptor propertyDescriptor) {
* Create a new BeanTypeDescriptor for the given bean property. super(componentType, methodParameter);
* @param propertyDescriptor the corresponding JavaBean PropertyDescriptor
* @param methodParameter the target method parameter
* @param type the specific type to expose (may be an array/collection element)
*/
public PropertyTypeDescriptor(PropertyDescriptor propertyDescriptor, MethodParameter methodParameter, Class<?> type) {
super(methodParameter, type);
this.propertyDescriptor = propertyDescriptor; this.propertyDescriptor = propertyDescriptor;
} }
/** /**
* Return the underlying PropertyDescriptor. * Return the underlying PropertyDescriptor.
*/ */
@ -72,58 +62,48 @@ public class PropertyTypeDescriptor extends TypeDescriptor {
return this.propertyDescriptor; return this.propertyDescriptor;
} }
public Annotation[] getAnnotations() { protected Annotation[] resolveAnnotations() {
Annotation[] anns = this.cachedAnnotations; Map<Class<?>, Annotation> annMap = new LinkedHashMap<Class<?>, Annotation>();
if (anns == null) { String name = this.propertyDescriptor.getName();
Map<Class<?>, Annotation> annMap = new LinkedHashMap<Class<?>, Annotation>(); if (StringUtils.hasLength(name)) {
String name = this.propertyDescriptor.getName(); Class<?> clazz = getMethodParameter().getMethod().getDeclaringClass();
if (StringUtils.hasLength(name)) { Field field = ReflectionUtils.findField(clazz, name);
Class<?> clazz = getMethodParameter().getMethod().getDeclaringClass(); if (field == null) {
Field field = ReflectionUtils.findField(clazz, name); // Same lenient fallback checking as in CachedIntrospectionResults...
field = ReflectionUtils.findField(clazz, name.substring(0, 1).toLowerCase() + name.substring(1));
if (field == null) { if (field == null) {
// Same lenient fallback checking as in CachedIntrospectionResults... field = ReflectionUtils.findField(clazz, name.substring(0, 1).toUpperCase() + name.substring(1));
field = ReflectionUtils.findField(clazz, name.substring(0, 1).toLowerCase() + name.substring(1));
if (field == null) {
field = ReflectionUtils.findField(clazz, name.substring(0, 1).toUpperCase() + name.substring(1));
}
}
if (field != null) {
for (Annotation ann : field.getAnnotations()) {
annMap.put(ann.annotationType(), ann);
}
} }
} }
Method writeMethod = this.propertyDescriptor.getWriteMethod(); if (field != null) {
Method readMethod = this.propertyDescriptor.getReadMethod(); for (Annotation ann : field.getAnnotations()) {
if (writeMethod != null && writeMethod != getMethodParameter().getMethod()) {
for (Annotation ann : writeMethod.getAnnotations()) {
annMap.put(ann.annotationType(), ann); annMap.put(ann.annotationType(), ann);
} }
} }
if (readMethod != null && readMethod != getMethodParameter().getMethod()) {
for (Annotation ann : readMethod.getAnnotations()) {
annMap.put(ann.annotationType(), ann);
}
}
for (Annotation ann : getMethodParameter().getMethodAnnotations()) {
annMap.put(ann.annotationType(), ann);
}
for (Annotation ann : getMethodParameter().getParameterAnnotations()) {
annMap.put(ann.annotationType(), ann);
}
anns = annMap.values().toArray(new Annotation[annMap.size()]);
this.cachedAnnotations = anns;
} }
return anns; Method writeMethod = this.propertyDescriptor.getWriteMethod();
Method readMethod = this.propertyDescriptor.getReadMethod();
if (writeMethod != null && writeMethod != getMethodParameter().getMethod()) {
for (Annotation ann : writeMethod.getAnnotations()) {
annMap.put(ann.annotationType(), ann);
}
}
if (readMethod != null && readMethod != getMethodParameter().getMethod()) {
for (Annotation ann : readMethod.getAnnotations()) {
annMap.put(ann.annotationType(), ann);
}
}
for (Annotation ann : getMethodParameter().getMethodAnnotations()) {
annMap.put(ann.annotationType(), ann);
}
for (Annotation ann : getMethodParameter().getParameterAnnotations()) {
annMap.put(ann.annotationType(), ann);
}
return annMap.values().toArray(new Annotation[annMap.size()]);
} }
public TypeDescriptor forElementType(Class<?> elementType) { public TypeDescriptor newComponentTypeDescriptor(Class<?> componentType, MethodParameter nested) {
if (elementType != null) { return new PropertyTypeDescriptor(componentType, nested, this.propertyDescriptor);
return new PropertyTypeDescriptor(this.propertyDescriptor, getMethodParameter(), elementType);
}
else {
return super.forElementType(null);
}
} }
} }

View File

@ -48,7 +48,6 @@ final class StringToCollectionConverter implements ConditionalGenericConverter {
return this.conversionService.canConvert(sourceType, targetType.getElementTypeDescriptor()); return this.conversionService.canConvert(sourceType, targetType.getElementTypeDescriptor());
} }
@SuppressWarnings("unchecked")
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (source == null) { if (source == null) {
return null; return null;
@ -57,8 +56,7 @@ final class StringToCollectionConverter implements ConditionalGenericConverter {
String[] fields = StringUtils.commaDelimitedListToStringArray(string); String[] fields = StringUtils.commaDelimitedListToStringArray(string);
Collection target = CollectionFactory.createCollection(targetType.getType(), fields.length); Collection target = CollectionFactory.createCollection(targetType.getType(), fields.length);
for (String sourceElement : fields) { for (String sourceElement : fields) {
Object targetElement = this.conversionService.convert(sourceElement.trim(), Object targetElement = this.conversionService.convert(sourceElement.trim(), sourceType, targetType.getElementTypeDescriptor());
sourceType, targetType.getElementTypeDescriptor(sourceElement));
target.add(targetElement); target.add(targetElement);
} }
return target; return target;

View File

@ -16,16 +16,17 @@
package org.springframework.core.convert; package org.springframework.core.convert;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import static junit.framework.Assert.assertEquals; import org.junit.Ignore;
import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
import org.junit.Test; import org.junit.Test;
/** /**
@ -47,7 +48,8 @@ public class TypeDescriptorTests {
public Map<String, Integer> mapField = new HashMap<String, Integer>(); public Map<String, Integer> mapField = new HashMap<String, Integer>();
public Map<String, List<Integer>> nestedMapField = new HashMap<String, List<Integer>>();
@Test @Test
public void listDescriptor() throws Exception { public void listDescriptor() throws Exception {
TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("listOfString")); TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("listOfString"));
@ -94,14 +96,27 @@ public class TypeDescriptorTests {
} }
@Test @Test
@Ignore
public void complexTypeDescriptor() throws Exception { public void complexTypeDescriptor() throws Exception {
TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("arrayOfListOfString")); TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("arrayOfListOfString"));
assertTrue(typeDescriptor.isArray()); assertTrue(typeDescriptor.isArray());
assertEquals(List.class,typeDescriptor.getElementType()); assertEquals(List.class,typeDescriptor.getElementType());
assertEquals(String.class, typeDescriptor.getElementTypeDescriptor().getElementType());
// TODO asc notice that the type of the list elements is lost: typeDescriptor.getElementType() should return a TypeDescriptor // TODO asc notice that the type of the list elements is lost: typeDescriptor.getElementType() should return a TypeDescriptor
assertEquals("java.util.List[]",typeDescriptor.asString()); assertEquals("java.util.List[]",typeDescriptor.asString());
} }
@Test
public void complexTypeDescriptor2() throws Exception {
TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("nestedMapField"));
assertTrue(typeDescriptor.isMap());
assertEquals(String.class,typeDescriptor.getMapKeyType());
assertEquals(List.class, typeDescriptor.getMapValueType());
assertEquals(Integer.class, typeDescriptor.getMapValueTypeDescriptor().getElementType());
assertEquals("java.util.Map<java.lang.String, java.util.List<java.lang.Integer>>", typeDescriptor.asString());
}
@Test @Test
public void testEquals() throws Exception { public void testEquals() throws Exception {
TypeDescriptor t1 = TypeDescriptor.valueOf(String.class); TypeDescriptor t1 = TypeDescriptor.valueOf(String.class);

View File

@ -16,6 +16,13 @@
package org.springframework.core.convert.support; package org.springframework.core.convert.support;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.awt.Color;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.AbstractList; import java.util.AbstractList;
@ -33,13 +40,14 @@ import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import static org.junit.Assert.*;
import org.junit.Test; import org.junit.Test;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.ConversionFailedException; import org.springframework.core.convert.ConversionFailedException;
import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.ConverterNotFoundException; import org.springframework.core.convert.ConverterNotFoundException;
import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterRegistry;
/** /**
* @author Keith Donald * @author Keith Donald
@ -286,6 +294,24 @@ public class DefaultConversionTests {
assertEquals(new Integer("3"), result.get(2)); assertEquals(new Integer("3"), result.get(2));
} }
@Test
public void testSpr7766() throws Exception {
ConverterRegistry registry = ((ConverterRegistry) conversionService);
registry.addConverter(new ColorConverter());
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());
assertEquals(Color.WHITE, colors.get(0));
assertEquals(Color.BLACK, colors.get(1));
}
public class ColorConverter implements Converter<String, Color> {
public Color convert(String source) { if (!source.startsWith("#")) source = "#" + source; return Color.decode(source); }
}
public void handlerMethod(List<Color> color) {
}
@Test @Test
public void convertArrayToCollectionImpl() { 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);

View File

@ -29,7 +29,7 @@ import org.springframework.core.convert.TypeDescriptor;
*/ */
public class TypedValue { public class TypedValue {
public static final TypedValue NULL = new TypedValue(null, TypeDescriptor.NULL); public static final TypedValue NULL = new TypedValue(null);
private final Object value; private final Object value;

View File

@ -44,7 +44,7 @@ public abstract class ExpressionUtils {
*/ */
public static <T> T convert(EvaluationContext context, Object value, Class<T> targetType) throws EvaluationException { public static <T> T convert(EvaluationContext context, Object value, Class<T> targetType) throws EvaluationException {
// TODO remove this function over time and use the one it delegates to // TODO remove this function over time and use the one it delegates to
return convertTypedValue(context,new TypedValue(value,TypeDescriptor.forObject(value)),targetType); return convertTypedValue(context,new TypedValue(value),targetType);
} }
/** /**

View File

@ -124,7 +124,7 @@ public class ExpressionState {
return TypedValue.NULL; return TypedValue.NULL;
} }
else { else {
return new TypedValue(value, TypeDescriptor.forObject(value)); return new TypedValue(value);
} }
} }
@ -183,7 +183,7 @@ public class ExpressionState {
OperatorOverloader overloader = this.relatedContext.getOperatorOverloader(); OperatorOverloader overloader = this.relatedContext.getOperatorOverloader();
if (overloader.overridesOperation(op, left, right)) { if (overloader.overridesOperation(op, left, right)) {
Object returnValue = overloader.operate(op, left, right); Object returnValue = overloader.operate(op, left, right);
return new TypedValue(returnValue,TypeDescriptor.forObject(returnValue)); return new TypedValue(returnValue);
} }
else { else {
String leftType = (left==null?"null":left.getClass().getName()); String leftType = (left==null?"null":left.getClass().getName());

View File

@ -17,8 +17,8 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.util.List;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.AccessException; import org.springframework.expression.AccessException;
@ -234,7 +234,6 @@ public class ConstructorReference extends SpelNodeImpl {
else { else {
componentType = arrayTypeCode.getType(); componentType = arrayTypeCode.getType();
} }
TypeDescriptor td = TypeDescriptor.valueOf(componentType);
Object newArray; Object newArray;
if (!hasInitializer()) { if (!hasInitializer()) {
// Confirm all dimensions were specified (for example [3][][5] is missing the 2nd dimension) // Confirm all dimensions were specified (for example [3][][5] is missing the 2nd dimension)
@ -313,7 +312,7 @@ public class ConstructorReference extends SpelNodeImpl {
throw new IllegalStateException(arrayTypeCode.name()); throw new IllegalStateException(arrayTypeCode.name());
} }
} }
return new TypedValue(newArray, td); return new TypedValue(newArray);
} }
private void populateReferenceTypeArray(ExpressionState state, Object newArray, TypeConverter typeConverter, private void populateReferenceTypeArray(ExpressionState state, Object newArray, TypeConverter typeConverter,

View File

@ -90,20 +90,10 @@ public class Indexer extends SpelNodeImpl {
// Indexing into a Map // Indexing into a Map
if (targetObject instanceof Map) { if (targetObject instanceof Map) {
if (targetObject == null) {
// Current decision: attempt to index into null map == exception and does not just return null
throw new SpelEvaluationException(getStartPosition(),SpelMessage.CANNOT_INDEX_INTO_NULL_VALUE);
}
Object possiblyConvertedKey = index; Object possiblyConvertedKey = index;
if (targetObjectTypeDescriptor.isMapEntryTypeKnown()) { possiblyConvertedKey = state.convertValue(index, targetObjectTypeDescriptor.getMapKeyTypeDescriptor());
possiblyConvertedKey = state.convertValue(index,TypeDescriptor.valueOf(targetObjectTypeDescriptor.getMapKeyType()));
}
Object o = ((Map<?, ?>) targetObject).get(possiblyConvertedKey); Object o = ((Map<?, ?>) targetObject).get(possiblyConvertedKey);
if (targetObjectTypeDescriptor.isMapEntryTypeKnown()) { return new TypedValue(o, targetObjectTypeDescriptor.getMapValueTypeDescriptor().applyType(o));
return new TypedValue(o, targetObjectTypeDescriptor.getMapValueTypeDescriptor());
} else {
return new TypedValue(o);
}
} }
if (targetObject == null) { if (targetObject == null) {
@ -125,7 +115,7 @@ public class Indexer extends SpelNodeImpl {
int pos = 0; int pos = 0;
for (Object o : c) { for (Object o : c) {
if (pos == idx) { if (pos == idx) {
return new TypedValue(o, targetObjectTypeDescriptor.getElementTypeDescriptor()); return new TypedValue(o, targetObjectTypeDescriptor.getElementTypeDescriptor().applyType(o));
} }
pos++; pos++;
} }
@ -195,10 +185,8 @@ public class Indexer extends SpelNodeImpl {
Map map = (Map)targetObject; Map map = (Map)targetObject;
Object possiblyConvertedKey = index; Object possiblyConvertedKey = index;
Object possiblyConvertedValue = newValue; Object possiblyConvertedValue = newValue;
if (targetObjectTypeDescriptor.isMapEntryTypeKnown()) { possiblyConvertedKey = state.convertValue(index.getValue(), targetObjectTypeDescriptor.getMapKeyTypeDescriptor());
possiblyConvertedKey = state.convertValue(index.getValue(),TypeDescriptor.valueOf(targetObjectTypeDescriptor.getMapKeyType())); possiblyConvertedValue = state.convertValue(newValue, targetObjectTypeDescriptor.getMapValueTypeDescriptor());
possiblyConvertedValue = state.convertValue(newValue,TypeDescriptor.valueOf(targetObjectTypeDescriptor.getMapValueType()));
}
map.put(possiblyConvertedKey,possiblyConvertedValue); map.put(possiblyConvertedKey,possiblyConvertedValue);
return; return;
} }

View File

@ -19,7 +19,6 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
@ -72,8 +71,7 @@ public class InlineList extends SpelNodeImpl {
constantList.add(((InlineList) child).getConstantValue()); constantList.add(((InlineList) child).getConstantValue());
} }
} }
this.constant = new TypedValue(Collections.unmodifiableList(constantList), TypeDescriptor this.constant = new TypedValue(Collections.unmodifiableList(constantList));
.valueOf(List.class));
} }
} }
@ -87,7 +85,7 @@ public class InlineList extends SpelNodeImpl {
for (int c = 0; c < childcount; c++) { for (int c = 0; c < childcount; c++) {
returnValue.add(getChild(c).getValue(expressionState)); returnValue.add(getChild(c).getValue(expressionState));
} }
return new TypedValue(returnValue, TypeDescriptor.valueOf(List.class)); return new TypedValue(returnValue);
} }
} }

View File

@ -16,7 +16,6 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.Operation; import org.springframework.expression.Operation;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
@ -50,7 +49,7 @@ public class OpDivide extends Operator {
} }
} }
Object result = state.operate(Operation.DIVIDE, operandOne, operandTwo); Object result = state.operate(Operation.DIVIDE, operandOne, operandTwo);
return new TypedValue(result,TypeDescriptor.forObject(result)); return new TypedValue(result);
} }
} }

View File

@ -68,14 +68,14 @@ public class Projection extends SpelNodeImpl {
List<Object> result = new ArrayList<Object>(); List<Object> result = new ArrayList<Object>();
for (Map.Entry entry : mapData.entrySet()) { for (Map.Entry entry : mapData.entrySet()) {
try { try {
state.pushActiveContextObject(new TypedValue(entry, TypeDescriptor.valueOf(Map.Entry.class))); state.pushActiveContextObject(new TypedValue(entry));
result.add(this.children[0].getValueInternal(state).getValue()); result.add(this.children[0].getValueInternal(state).getValue());
} }
finally { finally {
state.popActiveContextObject(); state.popActiveContextObject();
} }
} }
return new TypedValue(result,TypeDescriptor.valueOf(List.class)); // TODO unable to build correct type descriptor return new TypedValue(result); // TODO unable to build correct type descriptor
} }
else if (operand instanceof Collection || operandIsArray) { else if (operand instanceof Collection || operandIsArray) {
Collection<?> data = (operand instanceof Collection ? (Collection<?>) operand : Collection<?> data = (operand instanceof Collection ? (Collection<?>) operand :

View File

@ -74,7 +74,7 @@ public class Selection extends SpelNodeImpl {
Object lastKey = null; Object lastKey = null;
for (Map.Entry entry : mapdata.entrySet()) { for (Map.Entry entry : mapdata.entrySet()) {
try { try {
TypedValue kvpair = new TypedValue(entry,TypeDescriptor.valueOf(Map.Entry.class)); TypedValue kvpair = new TypedValue(entry);
state.pushActiveContextObject(kvpair); state.pushActiveContextObject(kvpair);
Object o = selectionCriteria.getValueInternal(state).getValue(); Object o = selectionCriteria.getValueInternal(state).getValue();
if (o instanceof Boolean) { if (o instanceof Boolean) {
@ -95,7 +95,7 @@ public class Selection extends SpelNodeImpl {
} }
} }
if ((variant == FIRST || variant == LAST) && result.size() == 0) { if ((variant == FIRST || variant == LAST) && result.size() == 0) {
return new TypedValue(null,TypeDescriptor.NULL); return new TypedValue(null);
} }
if (variant == LAST) { if (variant == LAST) {
Map resultMap = new HashMap(); Map resultMap = new HashMap();

View File

@ -16,7 +16,6 @@
package org.springframework.expression.spel.support; package org.springframework.expression.spel.support;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
/** /**
@ -31,7 +30,7 @@ public class BooleanTypedValue extends TypedValue {
private BooleanTypedValue(boolean b) { private BooleanTypedValue(boolean b) {
super(b, TypeDescriptor.valueOf(Boolean.class)); super(b);
} }

View File

@ -236,7 +236,7 @@ public class ReflectionHelper {
TypeDescriptor targetType; TypeDescriptor targetType;
if (varargsPosition != null && argPosition >= varargsPosition) { if (varargsPosition != null && argPosition >= varargsPosition) {
MethodParameter methodParam = MethodParameter.forMethodOrConstructor(methodOrCtor, varargsPosition); MethodParameter methodParam = MethodParameter.forMethodOrConstructor(methodOrCtor, varargsPosition);
targetType = new TypeDescriptor(methodParam, methodParam.getParameterType().getComponentType()); targetType = new TypeDescriptor(methodParam.getParameterType().getComponentType(), methodParam);
} }
else { else {
targetType = new TypeDescriptor(MethodParameter.forMethodOrConstructor(methodOrCtor, argPosition)); targetType = new TypeDescriptor(MethodParameter.forMethodOrConstructor(methodOrCtor, argPosition));
@ -268,7 +268,7 @@ public class ReflectionHelper {
TypeDescriptor targetType; TypeDescriptor targetType;
if (varargsPosition != null && argPosition >= varargsPosition) { if (varargsPosition != null && argPosition >= varargsPosition) {
MethodParameter methodParam = new MethodParameter(method, varargsPosition); MethodParameter methodParam = new MethodParameter(method, varargsPosition);
targetType = new TypeDescriptor(methodParam, methodParam.getParameterType().getComponentType()); targetType = new TypeDescriptor(methodParam.getParameterType().getComponentType(), methodParam);
} }
else { else {
targetType = new TypeDescriptor(new MethodParameter(method, argPosition)); targetType = new TypeDescriptor(new MethodParameter(method, argPosition));

View File

@ -18,7 +18,6 @@ package org.springframework.expression.spel.support;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.AccessException; import org.springframework.expression.AccessException;
import org.springframework.expression.ConstructorExecutor; import org.springframework.expression.ConstructorExecutor;
import org.springframework.expression.EvaluationContext; import org.springframework.expression.EvaluationContext;
@ -65,7 +64,7 @@ class ReflectiveConstructorExecutor implements ConstructorExecutor {
arguments = ReflectionHelper.setupArgumentsForVarargsInvocation(this.ctor.getParameterTypes(), arguments); arguments = ReflectionHelper.setupArgumentsForVarargsInvocation(this.ctor.getParameterTypes(), arguments);
} }
ReflectionUtils.makeAccessible(this.ctor); ReflectionUtils.makeAccessible(this.ctor);
return new TypedValue(this.ctor.newInstance(arguments), TypeDescriptor.valueOf(this.ctor.getDeclaringClass())); return new TypedValue(this.ctor.newInstance(arguments));
} }
catch (Exception ex) { catch (Exception ex) {
throw new AccessException("Problem invoking constructor: " + this.ctor, ex); throw new AccessException("Problem invoking constructor: " + this.ctor, ex);

View File

@ -80,7 +80,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
// The readerCache will only contain gettable properties (let's not worry about setters for now) // The readerCache will only contain gettable properties (let's not worry about setters for now)
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(name, method, null); PropertyDescriptor propertyDescriptor = new PropertyDescriptor(name, method, null);
TypeDescriptor typeDescriptor = TypeDescriptor typeDescriptor =
new PropertyTypeDescriptor(propertyDescriptor, new MethodParameter(method, -1)); new PropertyTypeDescriptor(new MethodParameter(method, -1), propertyDescriptor);
this.readerCache.put(cacheKey, new InvokerPair(method, typeDescriptor)); this.readerCache.put(cacheKey, new InvokerPair(method, typeDescriptor));
this.typeDescriptorCache.put(cacheKey, typeDescriptor); this.typeDescriptorCache.put(cacheKey, typeDescriptor);
return true; return true;
@ -128,7 +128,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
// The readerCache will only contain gettable properties (let's not worry about setters for now) // The readerCache will only contain gettable properties (let's not worry about setters for now)
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(name, method, null); PropertyDescriptor propertyDescriptor = new PropertyDescriptor(name, method, null);
TypeDescriptor typeDescriptor = TypeDescriptor typeDescriptor =
new PropertyTypeDescriptor(propertyDescriptor, new MethodParameter(method, -1)); new PropertyTypeDescriptor(new MethodParameter(method, -1), propertyDescriptor);
invoker = new InvokerPair(method, typeDescriptor); invoker = new InvokerPair(method, typeDescriptor);
this.readerCache.put(cacheKey, invoker); this.readerCache.put(cacheKey, invoker);
} }
@ -192,7 +192,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
throw new AccessException("Unable to access property '" + name + "' through setter "+method, ex); throw new AccessException("Unable to access property '" + name + "' through setter "+method, ex);
} }
MethodParameter mp = new MethodParameter(method,0); MethodParameter mp = new MethodParameter(method,0);
TypeDescriptor typeDescriptor = new PropertyTypeDescriptor(propertyDescriptor, mp); TypeDescriptor typeDescriptor = new PropertyTypeDescriptor(mp, propertyDescriptor);
this.writerCache.put(cacheKey, method); this.writerCache.put(cacheKey, method);
this.typeDescriptorCache.put(cacheKey, typeDescriptor); this.typeDescriptorCache.put(cacheKey, typeDescriptor);
return true; return true;

View File

@ -26,7 +26,6 @@ import java.util.Map;
import junit.framework.Assert; import junit.framework.Assert;
import org.junit.Test; import org.junit.Test;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.AccessException; import org.springframework.expression.AccessException;
import org.springframework.expression.EvaluationContext; import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
@ -247,7 +246,6 @@ public class ExpressionLanguageScenarioTests extends ExpressionTestCase {
private static class FruitColourAccessor implements PropertyAccessor { private static class FruitColourAccessor implements PropertyAccessor {
private static Map<String,Color> propertyMap = new HashMap<String,Color>(); private static Map<String,Color> propertyMap = new HashMap<String,Color>();
private static TypeDescriptor mapElementTypeDescriptor = TypeDescriptor.valueOf(Color.class);
static { static {
propertyMap.put("banana",Color.yellow); propertyMap.put("banana",Color.yellow);
@ -267,7 +265,7 @@ public class ExpressionLanguageScenarioTests extends ExpressionTestCase {
} }
public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException { public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
return new TypedValue(propertyMap.get(name),mapElementTypeDescriptor); return new TypedValue(propertyMap.get(name));
} }
public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException { public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException {
@ -306,7 +304,7 @@ public class ExpressionLanguageScenarioTests extends ExpressionTestCase {
} }
public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException { public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
return new TypedValue(propertyMap.get(name),TypeDescriptor.valueOf(Color.class)); return new TypedValue(propertyMap.get(name));
} }
public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException { public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException {

View File

@ -127,7 +127,7 @@ public class ExpressionStateTests extends ExpressionTestCase {
Assert.assertEquals(TypedValue.NULL,state.getRootContextObject()); Assert.assertEquals(TypedValue.NULL,state.getRootContextObject());
((StandardEvaluationContext)state.getEvaluationContext()).setRootObject(null,TypeDescriptor.NULL); ((StandardEvaluationContext)state.getEvaluationContext()).setRootObject(null);
Assert.assertEquals(null,state.getRootContextObject().getValue()); Assert.assertEquals(null,state.getRootContextObject().getValue());
} }

View File

@ -180,7 +180,7 @@ public class PropertyAccessTests extends ExpressionTestCase {
public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException { public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
if (!name.equals("flibbles")) if (!name.equals("flibbles"))
throw new RuntimeException("Assertion Failed! name should be flibbles"); throw new RuntimeException("Assertion Failed! name should be flibbles");
return new TypedValue(flibbles, TypeDescriptor.valueOf(String.class)); return new TypedValue(flibbles);
} }
public void write(EvaluationContext context, Object target, String name, Object newValue) public void write(EvaluationContext context, Object target, String name, Object newValue)

View File

@ -20,8 +20,8 @@ import java.lang.reflect.Method;
import java.util.List; import java.util.List;
import junit.framework.Assert; import junit.framework.Assert;
import org.junit.Test;
import org.junit.Test;
import org.springframework.core.MethodParameter; import org.springframework.core.MethodParameter;
import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.AccessException; import org.springframework.expression.AccessException;
@ -222,7 +222,7 @@ public class ScenariosForSpringSecurity extends ExpressionTestCase {
} }
public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException { public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
return new TypedValue(new Principal(),TypeDescriptor.valueOf(Principal.class)); return new TypedValue(new Principal());
} }
public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException { public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException {
@ -252,7 +252,7 @@ public class ScenariosForSpringSecurity extends ExpressionTestCase {
} }
public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException { public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
return new TypedValue(activePerson,TypeDescriptor.valueOf(Person.class)); return new TypedValue(activePerson);
} }
public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException { public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException {

View File

@ -69,6 +69,9 @@ public class SpelDocumentationTests extends ExpressionTestCase {
public Inventor[] Members = new Inventor[1]; public Inventor[] Members = new Inventor[1];
public List Members2 = new ArrayList(); public List Members2 = new ArrayList();
public Map<String,Object> officers = new HashMap<String,Object>(); public Map<String,Object> officers = new HashMap<String,Object>();
public List reverse = new ArrayList<Map<String, Object>>();
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
IEEE() { IEEE() {
officers.put("president",pupin); officers.put("president",pupin);
@ -77,6 +80,8 @@ public class SpelDocumentationTests extends ExpressionTestCase {
officers.put("advisors",linv); officers.put("advisors",linv);
Members2.add(tesla); Members2.add(tesla);
Members2.add(pupin); Members2.add(pupin);
reverse.add(officers);
} }
public boolean isMember(String name) { public boolean isMember(String name) {
@ -215,6 +220,9 @@ public class SpelDocumentationTests extends ExpressionTestCase {
parser.parseExpression("officers['advisors'][0].PlaceOfBirth.Country").setValue(societyContext, "Croatia"); parser.parseExpression("officers['advisors'][0].PlaceOfBirth.Country").setValue(societyContext, "Croatia");
Inventor i2 = parser.parseExpression("reverse[0]['advisors'][0]").getValue(societyContext,Inventor.class);
Assert.assertEquals("Nikola Tesla",i2.getName());
} }
// 7.5.3 // 7.5.3