Added conversion support for Java 8's ZoneId class and the 'of' method convention
Issue: SPR-1528
This commit is contained in:
		
							parent
							
								
									0c00b0d902
								
							
						
					
					
						commit
						c664010001
					
				|  | @ -65,6 +65,7 @@ import org.springframework.beans.propertyeditors.TimeZoneEditor; | ||||||
| import org.springframework.beans.propertyeditors.URIEditor; | import org.springframework.beans.propertyeditors.URIEditor; | ||||||
| import org.springframework.beans.propertyeditors.URLEditor; | import org.springframework.beans.propertyeditors.URLEditor; | ||||||
| import org.springframework.beans.propertyeditors.UUIDEditor; | import org.springframework.beans.propertyeditors.UUIDEditor; | ||||||
|  | import org.springframework.beans.propertyeditors.ZoneIdEditor; | ||||||
| import org.springframework.core.convert.ConversionService; | import org.springframework.core.convert.ConversionService; | ||||||
| import org.springframework.core.io.Resource; | import org.springframework.core.io.Resource; | ||||||
| import org.springframework.core.io.support.ResourceArrayPropertyEditor; | import org.springframework.core.io.support.ResourceArrayPropertyEditor; | ||||||
|  | @ -84,6 +85,19 @@ import org.springframework.util.ClassUtils; | ||||||
|  */ |  */ | ||||||
| public class PropertyEditorRegistrySupport implements PropertyEditorRegistry { | public class PropertyEditorRegistrySupport implements PropertyEditorRegistry { | ||||||
| 
 | 
 | ||||||
|  | 	private static Class<?> zoneIdClass; | ||||||
|  | 
 | ||||||
|  | 	static { | ||||||
|  | 		try { | ||||||
|  | 			zoneIdClass = PropertyEditorRegistrySupport.class.getClassLoader().loadClass("java.time.ZoneId"); | ||||||
|  | 		} | ||||||
|  | 		catch (ClassNotFoundException ex) { | ||||||
|  | 			// Java 8 ZoneId class not available | ||||||
|  | 			zoneIdClass = null; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| 	private ConversionService conversionService; | 	private ConversionService conversionService; | ||||||
| 
 | 
 | ||||||
| 	private boolean defaultEditorsActive = false; | 	private boolean defaultEditorsActive = false; | ||||||
|  | @ -202,6 +216,9 @@ public class PropertyEditorRegistrySupport implements PropertyEditorRegistry { | ||||||
| 		this.defaultEditors.put(URI.class, new URIEditor()); | 		this.defaultEditors.put(URI.class, new URIEditor()); | ||||||
| 		this.defaultEditors.put(URL.class, new URLEditor()); | 		this.defaultEditors.put(URL.class, new URLEditor()); | ||||||
| 		this.defaultEditors.put(UUID.class, new UUIDEditor()); | 		this.defaultEditors.put(UUID.class, new UUIDEditor()); | ||||||
|  | 		if (zoneIdClass != null) { | ||||||
|  | 			this.defaultEditors.put(zoneIdClass, new ZoneIdEditor()); | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		// Default instances of collection editors. | 		// Default instances of collection editors. | ||||||
| 		// Can be overridden by registering custom instances of those as custom editors. | 		// Can be overridden by registering custom instances of those as custom editors. | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| /* | /* | ||||||
|  * Copyright 2002-2012 the original author or authors. |  * Copyright 2002-2013 the original author or authors. | ||||||
|  * |  * | ||||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  * you may not use this file except in compliance with the License. |  * you may not use this file except in compliance with the License. | ||||||
|  | @ -21,11 +21,12 @@ import java.util.TimeZone; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Editor for {@code java.util.TimeZone}, translating timezone IDs into |  * Editor for {@code java.util.TimeZone}, translating timezone IDs into | ||||||
|  * TimeZone objects. Does not expose a text representation for TimeZone objects. |  * TimeZone objects. Exposed the TimeZone ID as a text representation. | ||||||
|  * |  * | ||||||
|  * @author Juergen Hoeller |  * @author Juergen Hoeller | ||||||
|  * @since 3.0 |  * @since 3.0 | ||||||
|  * @see java.util.TimeZone |  * @see java.util.TimeZone | ||||||
|  |  * @see ZoneIdEditor | ||||||
|  */ |  */ | ||||||
| public class TimeZoneEditor extends PropertyEditorSupport { | public class TimeZoneEditor extends PropertyEditorSupport { | ||||||
| 
 | 
 | ||||||
|  | @ -34,13 +35,10 @@ public class TimeZoneEditor extends PropertyEditorSupport { | ||||||
| 		setValue(TimeZone.getTimeZone(text)); | 		setValue(TimeZone.getTimeZone(text)); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** |  | ||||||
| 	 * This implementation returns {@code null} to indicate that |  | ||||||
| 	 * there is no appropriate text representation. |  | ||||||
| 	 */ |  | ||||||
| 	@Override | 	@Override | ||||||
| 	public String getAsText() { | 	public String getAsText() { | ||||||
| 		return null; | 		TimeZone value = (TimeZone) getValue(); | ||||||
|  | 		return (value != null ? value.getID() : ""); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -0,0 +1,44 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright 2002-2013 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.beans.propertyeditors; | ||||||
|  | 
 | ||||||
|  | import java.beans.PropertyEditorSupport; | ||||||
|  | import java.time.ZoneId; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Editor for {@code java.time.ZoneId}, translating zone ID Strings into | ||||||
|  |  * ZoneId objects. Exposed the TimeZone ID as a text representation. | ||||||
|  |  * | ||||||
|  |  * @author Juergen Hoeller | ||||||
|  |  * @since 4.0 | ||||||
|  |  * @see java.time.ZoneId | ||||||
|  |  * @see TimeZoneEditor | ||||||
|  |  */ | ||||||
|  | public class ZoneIdEditor extends PropertyEditorSupport { | ||||||
|  | 
 | ||||||
|  | 	@Override | ||||||
|  | 	public void setAsText(String text) throws IllegalArgumentException { | ||||||
|  | 		setValue(ZoneId.of(text)); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	@Override | ||||||
|  | 	public String getAsText() { | ||||||
|  | 		ZoneId value = (ZoneId) getValue(); | ||||||
|  | 		return (value != null ? value.getId() : ""); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| /* | /* | ||||||
|  * Copyright 2002-2012 the original author or authors. |  * Copyright 2002-2013 the original author or authors. | ||||||
|  * |  * | ||||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  * you may not use this file except in compliance with the License. |  * you may not use this file except in compliance with the License. | ||||||
|  | @ -29,13 +29,13 @@ import org.springframework.util.ClassUtils; | ||||||
| import org.springframework.util.ReflectionUtils; | import org.springframework.util.ReflectionUtils; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Generic Converter that attempts to convert a source Object to a target type |  * Generic converter that attempts to convert a source Object to a target type | ||||||
|  * by delegating to methods on the target type. |  * by delegating to methods on the target type. | ||||||
|  * |  * | ||||||
|  * <p>Calls the static {@code valueOf(sourceType)} method on the target type |  * <p>Calls a static {@code valueOf(sourceType)} or Java 8 style {@code of(sourceType)} method | ||||||
|  * to perform the conversion, if such a method exists. Else calls the target type's |  * on the target type to perform the conversion, if such a method exists. Otherwise, it calls | ||||||
|  * Constructor that accepts a single sourceType argument, if such a Constructor exists. |  * the target type's constructor that accepts a single {@code sourceType} argument, if such | ||||||
|  * Else throws a ConversionFailedException. |  * a constructor exists. If neither strategy works, it throws a ConversionFailedException. | ||||||
|  * |  * | ||||||
|  * @author Keith Donald |  * @author Keith Donald | ||||||
|  * @author Juergen Hoeller |  * @author Juergen Hoeller | ||||||
|  | @ -92,7 +92,11 @@ final class ObjectToObjectConverter implements ConditionalGenericConverter { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	private static Method getValueOfMethodOn(Class<?> clazz, Class<?> sourceParameterType) { | 	private static Method getValueOfMethodOn(Class<?> clazz, Class<?> sourceParameterType) { | ||||||
| 		return ClassUtils.getStaticMethod(clazz, "valueOf", sourceParameterType); | 		Method method = ClassUtils.getStaticMethod(clazz, "valueOf", sourceParameterType); | ||||||
|  | 		if (method == null) { | ||||||
|  | 			method = ClassUtils.getStaticMethod(clazz, "of", sourceParameterType); | ||||||
|  | 		} | ||||||
|  | 		return method; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	private static Constructor<?> getConstructor(Class<?> clazz, Class<?> sourceParameterType) { | 	private static Constructor<?> getConstructor(Class<?> clazz, Class<?> sourceParameterType) { | ||||||
|  |  | ||||||
|  | @ -16,19 +16,10 @@ | ||||||
| 
 | 
 | ||||||
| package org.springframework.core.convert.support; | package org.springframework.core.convert.support; | ||||||
| 
 | 
 | ||||||
| import static org.hamcrest.Matchers.equalTo; |  | ||||||
| import static org.junit.Assert.*; |  | ||||||
| import static org.junit.Assert.assertArrayEquals; |  | ||||||
| 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.assertThat; |  | ||||||
| import static org.junit.Assert.assertTrue; |  | ||||||
| 
 |  | ||||||
| import java.awt.Color; | import java.awt.Color; | ||||||
| import java.math.BigDecimal; | import java.math.BigDecimal; | ||||||
| import java.math.BigInteger; | import java.math.BigInteger; | ||||||
|  | import java.time.ZoneId; | ||||||
| import java.util.AbstractList; | import java.util.AbstractList; | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| import java.util.Arrays; | import java.util.Arrays; | ||||||
|  | @ -45,6 +36,7 @@ import java.util.Properties; | ||||||
| import java.util.Set; | import java.util.Set; | ||||||
| 
 | 
 | ||||||
| import org.junit.Test; | import org.junit.Test; | ||||||
|  | 
 | ||||||
| import org.springframework.core.MethodParameter; | import org.springframework.core.MethodParameter; | ||||||
| import org.springframework.core.convert.ConversionFailedException; | import org.springframework.core.convert.ConversionFailedException; | ||||||
| import org.springframework.core.convert.ConverterNotFoundException; | import org.springframework.core.convert.ConverterNotFoundException; | ||||||
|  | @ -52,6 +44,9 @@ import org.springframework.core.convert.TypeDescriptor; | ||||||
| import org.springframework.core.convert.converter.Converter; | import org.springframework.core.convert.converter.Converter; | ||||||
| import org.springframework.core.convert.converter.ConverterRegistry; | import org.springframework.core.convert.converter.ConverterRegistry; | ||||||
| 
 | 
 | ||||||
|  | import static org.hamcrest.Matchers.*; | ||||||
|  | import static org.junit.Assert.*; | ||||||
|  | 
 | ||||||
| /** | /** | ||||||
|  * @author Keith Donald |  * @author Keith Donald | ||||||
|  * @author Juergen Hoeller |  * @author Juergen Hoeller | ||||||
|  | @ -709,6 +704,11 @@ public class DefaultConversionTests { | ||||||
| 		assertEquals("123456789", conversionService.convert(new SSN("123456789"), String.class)); | 		assertEquals("123456789", conversionService.convert(new SSN("123456789"), String.class)); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	@Test | ||||||
|  | 	public void convertObjectToStringWithJavaTimeOfMethodPresent() { | ||||||
|  | 		assertTrue(conversionService.convert(ZoneId.of("GMT+1"), String.class).startsWith("GMT+")); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	@Test | 	@Test | ||||||
| 	public void convertObjectToStringNotSupported() { | 	public void convertObjectToStringNotSupported() { | ||||||
| 		assertFalse(conversionService.canConvert(TestEntity.class, String.class)); | 		assertFalse(conversionService.canConvert(TestEntity.class, String.class)); | ||||||
|  | @ -725,73 +725,16 @@ public class DefaultConversionTests { | ||||||
| 		assertEquals("123456789", conversionService.convert(new SSN("123456789"), String.class)); | 		assertEquals("123456789", conversionService.convert(new SSN("123456789"), String.class)); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	@Test | ||||||
|  | 	public void convertObjectToObjectWithJavaTimeOfMethod() { | ||||||
|  | 		assertEquals(ZoneId.of("GMT+1"), conversionService.convert("GMT+1", ZoneId.class)); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	@Test(expected=ConverterNotFoundException.class) | 	@Test(expected=ConverterNotFoundException.class) | ||||||
| 	public void convertObjectToObjectNoValueOFMethodOrConstructor() { | 	public void convertObjectToObjectNoValueOFMethodOrConstructor() { | ||||||
| 		conversionService.convert(new Long(3), SSN.class); | 		conversionService.convert(new Long(3), SSN.class); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	public Object assignableTarget; |  | ||||||
| 
 |  | ||||||
| 	private static class SSN { |  | ||||||
| 
 |  | ||||||
| 		private String value; |  | ||||||
| 
 |  | ||||||
| 		public SSN(String value) { |  | ||||||
| 			this.value = value; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		@Override |  | ||||||
| 		public boolean equals(Object o) { |  | ||||||
| 			if (!(o instanceof SSN)) { |  | ||||||
| 				return false; |  | ||||||
| 			} |  | ||||||
| 			SSN ssn = (SSN) o; |  | ||||||
| 			return this.value.equals(ssn.value); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		@Override |  | ||||||
| 		public int hashCode() { |  | ||||||
| 			return value.hashCode(); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		@Override |  | ||||||
| 		public String toString() { |  | ||||||
| 			return value; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	private static class ISBN { |  | ||||||
| 
 |  | ||||||
| 		private String value; |  | ||||||
| 
 |  | ||||||
| 		private ISBN(String value) { |  | ||||||
| 			this.value = value; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		@Override |  | ||||||
| 		public boolean equals(Object o) { |  | ||||||
| 			if (!(o instanceof ISBN)) { |  | ||||||
| 				return false; |  | ||||||
| 			} |  | ||||||
| 			ISBN isbn = (ISBN) o; |  | ||||||
| 			return this.value.equals(isbn.value); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		@Override |  | ||||||
| 		public int hashCode() { |  | ||||||
| 			return value.hashCode(); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		@Override |  | ||||||
| 		public String toString() { |  | ||||||
| 			return value; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		public static ISBN valueOf(String value) { |  | ||||||
| 			return new ISBN(value); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@Test | 	@Test | ||||||
| 	public void convertObjectToObjectFinderMethod() { | 	public void convertObjectToObjectFinderMethod() { | ||||||
| 		TestEntity e = conversionService.convert(1L, TestEntity.class); | 		TestEntity e = conversionService.convert(1L, TestEntity.class); | ||||||
|  | @ -864,4 +807,66 @@ public class DefaultConversionTests { | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	public Object assignableTarget; | ||||||
|  | 
 | ||||||
|  | 	private static class SSN { | ||||||
|  | 
 | ||||||
|  | 		private String value; | ||||||
|  | 
 | ||||||
|  | 		public SSN(String value) { | ||||||
|  | 			this.value = value; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		@Override | ||||||
|  | 		public boolean equals(Object o) { | ||||||
|  | 			if (!(o instanceof SSN)) { | ||||||
|  | 				return false; | ||||||
|  | 			} | ||||||
|  | 			SSN ssn = (SSN) o; | ||||||
|  | 			return this.value.equals(ssn.value); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		@Override | ||||||
|  | 		public int hashCode() { | ||||||
|  | 			return value.hashCode(); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		@Override | ||||||
|  | 		public String toString() { | ||||||
|  | 			return value; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	private static class ISBN { | ||||||
|  | 
 | ||||||
|  | 		private String value; | ||||||
|  | 
 | ||||||
|  | 		private ISBN(String value) { | ||||||
|  | 			this.value = value; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		@Override | ||||||
|  | 		public boolean equals(Object o) { | ||||||
|  | 			if (!(o instanceof ISBN)) { | ||||||
|  | 				return false; | ||||||
|  | 			} | ||||||
|  | 			ISBN isbn = (ISBN) o; | ||||||
|  | 			return this.value.equals(isbn.value); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		@Override | ||||||
|  | 		public int hashCode() { | ||||||
|  | 			return value.hashCode(); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		@Override | ||||||
|  | 		public String toString() { | ||||||
|  | 			return value; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		public static ISBN valueOf(String value) { | ||||||
|  | 			return new ISBN(value); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue