diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/TypeConverterDelegate.java b/org.springframework.beans/src/main/java/org/springframework/beans/TypeConverterDelegate.java index 049a069438..b9b05e1878 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/TypeConverterDelegate.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/TypeConverterDelegate.java @@ -194,7 +194,7 @@ class TypeConverterDelegate { // No custom editor but custom ConversionService specified? ConversionService conversionService = this.propertyEditorRegistry.getConversionService(); if (editor == null && conversionService != null && convertedValue != null) { - TypeDescriptor sourceTypeDesc = TypeDescriptor.valueOf(convertedValue.getClass()); + TypeDescriptor sourceTypeDesc = new TypeDescriptor(convertedValue); if (conversionService.canConvert(sourceTypeDesc, typeDescriptor)) { return (T) conversionService.convert(convertedValue, sourceTypeDesc, typeDescriptor); } diff --git a/org.springframework.context/src/test/java/org/springframework/context/conversionservice/Bar.java b/org.springframework.context/src/test/java/org/springframework/context/conversionservice/Bar.java index d61b6100e5..b89f6274ad 100644 --- a/org.springframework.context/src/test/java/org/springframework/context/conversionservice/Bar.java +++ b/org.springframework.context/src/test/java/org/springframework/context/conversionservice/Bar.java @@ -1,5 +1,24 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.springframework.context.conversionservice; +/** + * @author Keith Donald + */ public class Bar { private String value; @@ -11,4 +30,5 @@ public class Bar { public String getValue() { return value; } + } diff --git a/org.springframework.context/src/test/java/org/springframework/context/conversionservice/ConversionServiceContextConfigTests.java b/org.springframework.context/src/test/java/org/springframework/context/conversionservice/ConversionServiceContextConfigTests.java index fc4b29fc33..60dd150dcb 100644 --- a/org.springframework.context/src/test/java/org/springframework/context/conversionservice/ConversionServiceContextConfigTests.java +++ b/org.springframework.context/src/test/java/org/springframework/context/conversionservice/ConversionServiceContextConfigTests.java @@ -1,16 +1,32 @@ -package org.springframework.context.conversionservice; +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +package org.springframework.context.conversionservice; -import org.junit.Ignore; +import static org.junit.Assert.*; import org.junit.Test; + import org.springframework.context.support.ClassPathXmlApplicationContext; +/** + * @author Keith Donald + */ public class ConversionServiceContextConfigTests { @Test - @Ignore public void testConfigOk() { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("org/springframework/context/conversionservice/conversionService.xml"); TestClient client = context.getBean("testClient", TestClient.class); diff --git a/org.springframework.context/src/test/java/org/springframework/context/conversionservice/StringToBarConverter.java b/org.springframework.context/src/test/java/org/springframework/context/conversionservice/StringToBarConverter.java index 1d7f911f18..5248cb2644 100644 --- a/org.springframework.context/src/test/java/org/springframework/context/conversionservice/StringToBarConverter.java +++ b/org.springframework.context/src/test/java/org/springframework/context/conversionservice/StringToBarConverter.java @@ -1,7 +1,26 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.springframework.context.conversionservice; import org.springframework.core.convert.converter.Converter; +/** + * @author Keith Donald + */ public class StringToBarConverter implements Converter { public Bar convert(String source) { diff --git a/org.springframework.context/src/test/java/org/springframework/context/conversionservice/TestClient.java b/org.springframework.context/src/test/java/org/springframework/context/conversionservice/TestClient.java index c78f8fdf9c..c8e460707b 100644 --- a/org.springframework.context/src/test/java/org/springframework/context/conversionservice/TestClient.java +++ b/org.springframework.context/src/test/java/org/springframework/context/conversionservice/TestClient.java @@ -1,15 +1,44 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.springframework.context.conversionservice; import java.util.List; +import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.Resource; +/** + * @author Keith Donald + * @author Juergen Hoeller + */ public class TestClient { private List bars; private boolean bool; + private Resource[] resourceArray; + + private List resourceList; + + private Map resourceMap; + + public List getBars() { return bars; } @@ -27,4 +56,28 @@ public class TestClient { this.bool = bool; } + public Resource[] getResourceArray() { + return resourceArray; + } + + public void setResourceArray(Resource[] resourceArray) { + this.resourceArray = resourceArray; + } + + public List getResourceList() { + return resourceList; + } + + public void setResourceList(List resourceList) { + this.resourceList = resourceList; + } + + public Map getResourceMap() { + return resourceMap; + } + + public void setResourceMap(Map resourceMap) { + this.resourceMap = resourceMap; + } + } diff --git a/org.springframework.context/src/test/resources/org/springframework/context/conversionservice/conversionService.xml b/org.springframework.context/src/test/resources/org/springframework/context/conversionservice/conversionService.xml index 64e86fc706..63223400b5 100644 --- a/org.springframework.context/src/test/resources/org/springframework/context/conversionservice/conversionService.xml +++ b/org.springframework.context/src/test/resources/org/springframework/context/conversionservice/conversionService.xml @@ -5,7 +5,7 @@ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd"> - + @@ -13,6 +13,20 @@ + + classpath:test.xml + + + + classpath:test.xml + + + + + + + + diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/TypeDescriptor.java b/org.springframework.core/src/main/java/org/springframework/core/convert/TypeDescriptor.java index a953687447..435873073b 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/TypeDescriptor.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/TypeDescriptor.java @@ -47,6 +47,8 @@ public class TypeDescriptor { public static final TypeDescriptor STRING = TypeDescriptor.valueOf(String.class); + private Object value; + private Class type; private TypeDescriptor elementType; @@ -58,10 +60,22 @@ public class TypeDescriptor { private Annotation[] cachedFieldAnnotations; + /** + * Create a new descriptor for the type of the given value. + *

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 type the actual type to wrap + */ + public 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. - *

Use this constructor when a conversion point comes from a source such as a Map - * or Collection, where no additional context is available. + *

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 */ public TypeDescriptor(Class type) { @@ -242,6 +256,7 @@ public class TypeDescriptor { * Determine the generic key type of the wrapped Map parameter/field, if any. * @return the generic type, or null if none */ + @SuppressWarnings("unchecked") public Class getMapKeyType() { if (this.field != null) { return GenericCollectionTypeResolver.getMapKeyFieldType(field); @@ -249,6 +264,18 @@ public class TypeDescriptor { else if (this.methodParameter != null) { return GenericCollectionTypeResolver.getMapKeyParameterType(this.methodParameter); } + else if (this.value instanceof Map) { + Map map = (Map) this.value; + if (!map.isEmpty()) { + Object key = map.keySet().iterator().next(); + if (key != null) { + return key.getClass(); + } + } + } + if (this.type != null) { + return GenericCollectionTypeResolver.getMapKeyType((Class) this.type); + } else { return null; } @@ -258,6 +285,7 @@ public class TypeDescriptor { * Determine the generic value type of the wrapped Map parameter/field, if any. * @return the generic type, or null if none */ + @SuppressWarnings("unchecked") public Class getMapValueType() { if (this.field != null) { return GenericCollectionTypeResolver.getMapValueFieldType(this.field); @@ -265,6 +293,18 @@ public class TypeDescriptor { else if (this.methodParameter != null) { return GenericCollectionTypeResolver.getMapValueParameterType(this.methodParameter); } + else if (this.value instanceof Map) { + Map map = (Map) this.value; + if (!map.isEmpty()) { + Object val = map.values().iterator().next(); + if (val != null) { + return val.getClass(); + } + } + } + if (this.type != null) { + return GenericCollectionTypeResolver.getMapValueType((Class) this.type); + } else { return null; } @@ -349,14 +389,26 @@ public class TypeDescriptor { @SuppressWarnings("unchecked") private Class getCollectionElementType() { + if (this.field != null) { + return GenericCollectionTypeResolver.getCollectionFieldType(this.field); + } + else if (this.methodParameter != null) { + return GenericCollectionTypeResolver.getCollectionParameterType(this.methodParameter); + } + else if (this.value instanceof Collection) { + Collection coll = (Collection) this.value; + if (!coll.isEmpty()) { + Object elem = coll.iterator().next(); + if (elem != null) { + return elem.getClass(); + } + } + } if (this.type != null) { return GenericCollectionTypeResolver.getCollectionType((Class) this.type); } - else if (this.field != null) { - return GenericCollectionTypeResolver.getCollectionFieldType(this.field); - } else { - return GenericCollectionTypeResolver.getCollectionParameterType(this.methodParameter); + return null; } } diff --git a/org.springframework.core/src/test/java/org/springframework/core/io/support/ResourceArrayPropertyEditorTests.java b/org.springframework.core/src/test/java/org/springframework/core/io/support/ResourceArrayPropertyEditorTests.java index f386788e51..d861ac89de 100644 --- a/org.springframework.core/src/test/java/org/springframework/core/io/support/ResourceArrayPropertyEditorTests.java +++ b/org.springframework.core/src/test/java/org/springframework/core/io/support/ResourceArrayPropertyEditorTests.java @@ -1,15 +1,33 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.springframework.core.io.support; import static org.junit.Assert.*; - import org.junit.Test; -import org.springframework.core.io.Resource; +import org.springframework.core.io.Resource; +/** + * @author Dave Syer + */ public class ResourceArrayPropertyEditorTests { - + private ResourceArrayPropertyEditor editor = new ResourceArrayPropertyEditor(); - + @Test public void testVanillaResource() throws Exception { editor.setAsText("classpath:org/springframework/core/io/support/ResourceArrayPropertyEditor.class");