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.URLEditor; | ||||
| import org.springframework.beans.propertyeditors.UUIDEditor; | ||||
| import org.springframework.beans.propertyeditors.ZoneIdEditor; | ||||
| import org.springframework.core.convert.ConversionService; | ||||
| import org.springframework.core.io.Resource; | ||||
| import org.springframework.core.io.support.ResourceArrayPropertyEditor; | ||||
|  | @ -84,6 +85,19 @@ import org.springframework.util.ClassUtils; | |||
|  */ | ||||
| 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 boolean defaultEditorsActive = false; | ||||
|  | @ -202,6 +216,9 @@ public class PropertyEditorRegistrySupport implements PropertyEditorRegistry { | |||
| 		this.defaultEditors.put(URI.class, new URIEditor()); | ||||
| 		this.defaultEditors.put(URL.class, new URLEditor()); | ||||
| 		this.defaultEditors.put(UUID.class, new UUIDEditor()); | ||||
| 		if (zoneIdClass != null) { | ||||
| 			this.defaultEditors.put(zoneIdClass, new ZoneIdEditor()); | ||||
| 		} | ||||
| 
 | ||||
| 		// Default instances of collection 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"); | ||||
|  * 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 | ||||
|  * TimeZone objects. Does not expose a text representation for TimeZone objects. | ||||
|  * TimeZone objects. Exposed the TimeZone ID as a text representation. | ||||
|  * | ||||
|  * @author Juergen Hoeller | ||||
|  * @since 3.0 | ||||
|  * @see java.util.TimeZone | ||||
|  * @see ZoneIdEditor | ||||
|  */ | ||||
| public class TimeZoneEditor extends PropertyEditorSupport { | ||||
| 
 | ||||
|  | @ -34,13 +35,10 @@ public class TimeZoneEditor extends PropertyEditorSupport { | |||
| 		setValue(TimeZone.getTimeZone(text)); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * This implementation returns {@code null} to indicate that | ||||
| 	 * there is no appropriate text representation. | ||||
| 	 */ | ||||
| 	@Override | ||||
| 	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"); | ||||
|  * 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; | ||||
| 
 | ||||
| /** | ||||
|  * 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. | ||||
|  * | ||||
|  * <p>Calls the static {@code valueOf(sourceType)} method on the target type | ||||
|  * to perform the conversion, if such a method exists. Else calls the target type's | ||||
|  * Constructor that accepts a single sourceType argument, if such a Constructor exists. | ||||
|  * Else throws a ConversionFailedException. | ||||
|  * <p>Calls a static {@code valueOf(sourceType)} or Java 8 style {@code of(sourceType)} method | ||||
|  * on the target type to perform the conversion, if such a method exists. Otherwise, it calls | ||||
|  * the target type's constructor that accepts a single {@code sourceType} argument, if such | ||||
|  * a constructor exists. If neither strategy works, it throws a ConversionFailedException. | ||||
|  * | ||||
|  * @author Keith Donald | ||||
|  * @author Juergen Hoeller | ||||
|  | @ -92,7 +92,11 @@ final class ObjectToObjectConverter implements ConditionalGenericConverter { | |||
| 	} | ||||
| 
 | ||||
| 	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) { | ||||
|  |  | |||
|  | @ -16,19 +16,10 @@ | |||
| 
 | ||||
| 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.math.BigDecimal; | ||||
| import java.math.BigInteger; | ||||
| import java.time.ZoneId; | ||||
| import java.util.AbstractList; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Arrays; | ||||
|  | @ -45,6 +36,7 @@ import java.util.Properties; | |||
| import java.util.Set; | ||||
| 
 | ||||
| import org.junit.Test; | ||||
| 
 | ||||
| import org.springframework.core.MethodParameter; | ||||
| import org.springframework.core.convert.ConversionFailedException; | ||||
| 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.ConverterRegistry; | ||||
| 
 | ||||
| import static org.hamcrest.Matchers.*; | ||||
| import static org.junit.Assert.*; | ||||
| 
 | ||||
| /** | ||||
|  * @author Keith Donald | ||||
|  * @author Juergen Hoeller | ||||
|  | @ -709,6 +704,11 @@ public class DefaultConversionTests { | |||
| 		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 | ||||
| 	public void convertObjectToStringNotSupported() { | ||||
| 		assertFalse(conversionService.canConvert(TestEntity.class, String.class)); | ||||
|  | @ -725,73 +725,16 @@ public class DefaultConversionTests { | |||
| 		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) | ||||
| 	public void convertObjectToObjectNoValueOFMethodOrConstructor() { | ||||
| 		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 | ||||
| 	public void convertObjectToObjectFinderMethod() { | ||||
| 		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