提交 4b5208fa 编写于 作者: C Chris Beams

Introduce PropertyResolver#getPropertyAsClass

上级 275d43df
...@@ -196,6 +196,10 @@ public abstract class AbstractEnvironment implements ConfigurableEnvironment { ...@@ -196,6 +196,10 @@ public abstract class AbstractEnvironment implements ConfigurableEnvironment {
return this.propertyResolver.getProperty(key, targetType); return this.propertyResolver.getProperty(key, targetType);
} }
public <T> Class<T> getPropertyAsClass(String key, Class<T> targetType) {
return this.propertyResolver.getPropertyAsClass(key, targetType);
}
public String getRequiredProperty(String key) throws IllegalStateException { public String getRequiredProperty(String key) throws IllegalStateException {
return this.propertyResolver.getRequiredProperty(key); return this.propertyResolver.getRequiredProperty(key);
} }
......
...@@ -41,6 +41,15 @@ public interface PropertyResolver { ...@@ -41,6 +41,15 @@ public interface PropertyResolver {
*/ */
<T> T getProperty(String key, Class<T> targetType); <T> T getProperty(String key, Class<T> targetType);
/**
* Convert the property value associated with the given key to a {@code Class}
* of type {@code T} or {@code null} if the key cannot be resolved.
* @throws ConversionException if class specified by property value cannot be found
* or loaded or if targetType is not assignable from class specified by property value
* @see #getProperty(String, Class)
*/
<T> Class<T> getPropertyAsClass(String key, Class<T> targetType);
/** /**
* Return the property value associated with the given key, converted to the given * Return the property value associated with the given key, converted to the given
* targetType (never {@code null}). * targetType (never {@code null}).
......
...@@ -18,6 +18,9 @@ package org.springframework.core.env; ...@@ -18,6 +18,9 @@ package org.springframework.core.env;
import static java.lang.String.format; import static java.lang.String.format;
import org.springframework.core.convert.ConversionException;
import org.springframework.util.ClassUtils;
/** /**
* {@link PropertyResolver} implementation that resolves property values against * {@link PropertyResolver} implementation that resolves property values against
* an underlying set of {@link PropertySources}. * an underlying set of {@link PropertySources}.
...@@ -58,7 +61,7 @@ public class PropertySourcesPropertyResolver extends AbstractPropertyResolver { ...@@ -58,7 +61,7 @@ public class PropertySourcesPropertyResolver extends AbstractPropertyResolver {
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
logger.trace(format("getProperty(\"%s\", %s)", key, targetValueType.getSimpleName())); logger.trace(format("getProperty(\"%s\", %s)", key, targetValueType.getSimpleName()));
} }
for (PropertySource<?> propertySource : this.propertySources) { for (PropertySource<?> propertySource : this.propertySources) {
if (debugEnabled) { if (debugEnabled) {
logger.debug(format("Searching for key '%s' in [%s]", key, propertySource.getName())); logger.debug(format("Searching for key '%s' in [%s]", key, propertySource.getName()));
...@@ -79,11 +82,68 @@ public class PropertySourcesPropertyResolver extends AbstractPropertyResolver { ...@@ -79,11 +82,68 @@ public class PropertySourcesPropertyResolver extends AbstractPropertyResolver {
return conversionService.convert(value, targetValueType); return conversionService.convert(value, targetValueType);
} }
} }
if (debugEnabled) { if (debugEnabled) {
logger.debug(format("Could not find key '%s' in any property source. Returning [null]", key)); logger.debug(format("Could not find key '%s' in any property source. Returning [null]", key));
} }
return null; return null;
} }
public <T> Class<T> getPropertyAsClass(String key, Class<T> targetValueType) {
boolean debugEnabled = logger.isDebugEnabled();
if (logger.isTraceEnabled()) {
logger.trace(format("getPropertyAsClass(\"%s\", %s)", key, targetValueType.getSimpleName()));
}
for (PropertySource<?> propertySource : this.propertySources) {
if (debugEnabled) {
logger.debug(format("Searching for key '%s' in [%s]", key, propertySource.getName()));
}
Object value;
if ((value = propertySource.getProperty(key)) != null) {
if (debugEnabled) {
logger.debug(
format("Found key '%s' in [%s] with value '%s'", key, propertySource.getName(), value));
}
Class<?> clazz;
if (value instanceof String) {
try {
clazz = ClassUtils.forName((String)value, null);
} catch (Exception ex) {
throw new ClassConversionException((String)value, targetValueType, ex);
}
}
else if (value instanceof Class) {
clazz = (Class<?>)value;
} else {
clazz = value.getClass();
}
if (!targetValueType.isAssignableFrom(clazz)) {
throw new ClassConversionException(clazz, targetValueType);
}
@SuppressWarnings("unchecked")
Class<T> targetClass = (Class<T>)clazz;
return targetClass;
}
}
if (debugEnabled) {
logger.debug(format("Could not find key '%s' in any property source. Returning [null]", key));
}
return null;
}
@SuppressWarnings("serial")
static class ClassConversionException extends ConversionException {
public ClassConversionException(Class<?> actual, Class<?> expected) {
super(String.format("Actual type %s is not assignable to expected type %s", actual.getName(), expected.getName()));
}
public ClassConversionException(String actual, Class<?> expected, Exception ex) {
super(String.format("Could not find/load class %s during attempt to convert to %s", actual, expected.getName()), ex);
}
}
} }
...@@ -20,6 +20,7 @@ import static org.hamcrest.CoreMatchers.equalTo; ...@@ -20,6 +20,7 @@ import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue; import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import java.util.HashMap; import java.util.HashMap;
...@@ -28,6 +29,7 @@ import java.util.Properties; ...@@ -28,6 +29,7 @@ import java.util.Properties;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.springframework.core.convert.ConversionException;
import org.springframework.mock.env.MockPropertySource; import org.springframework.mock.env.MockPropertySource;
/** /**
...@@ -238,4 +240,70 @@ public class PropertySourcesPropertyResolverTests { ...@@ -238,4 +240,70 @@ public class PropertySourcesPropertyResolverTests {
new PropertySourcesPropertyResolver(new MutablePropertySources()).resolveRequiredPlaceholders(null); new PropertySourcesPropertyResolver(new MutablePropertySources()).resolveRequiredPlaceholders(null);
} }
@Test
public void getPropertyAsClass() throws ClassNotFoundException, LinkageError {
MutablePropertySources propertySources = new MutablePropertySources();
propertySources.addFirst(new MockPropertySource().withProperty("some.class", SpecificType.class.getName()));
PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources);
assertTrue(resolver.getPropertyAsClass("some.class", SomeType.class).equals(SpecificType.class));
}
@Test
public void getPropertyAsClass_withInterfaceAsTarget() throws ClassNotFoundException, LinkageError {
MutablePropertySources propertySources = new MutablePropertySources();
propertySources.addFirst(new MockPropertySource().withProperty("some.class", SomeType.class.getName()));
PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources);
assertTrue(resolver.getPropertyAsClass("some.class", SomeType.class).equals(SomeType.class));
}
@Test(expected=ConversionException.class)
public void getPropertyAsClass_withMismatchedTypeForValue() {
MutablePropertySources propertySources = new MutablePropertySources();
propertySources.addFirst(new MockPropertySource().withProperty("some.class", "java.lang.String"));
PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources);
resolver.getPropertyAsClass("some.class", SomeType.class);
}
@Test(expected=ConversionException.class)
public void getPropertyAsClass_withNonExistentClassForValue() {
MutablePropertySources propertySources = new MutablePropertySources();
propertySources.addFirst(new MockPropertySource().withProperty("some.class", "some.bogus.Class"));
PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources);
resolver.getPropertyAsClass("some.class", SomeType.class);
}
@Test
public void getPropertyAsClass_withObjectForValue() {
MutablePropertySources propertySources = new MutablePropertySources();
propertySources.addFirst(new MockPropertySource().withProperty("some.class", new SpecificType()));
PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources);
assertTrue(resolver.getPropertyAsClass("some.class", SomeType.class).equals(SpecificType.class));
}
@Test(expected=ConversionException.class)
public void getPropertyAsClass_withMismatchedObjectForValue() {
MutablePropertySources propertySources = new MutablePropertySources();
propertySources.addFirst(new MockPropertySource().withProperty("some.class", new Integer(42)));
PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources);
resolver.getPropertyAsClass("some.class", SomeType.class);
}
@Test
public void getPropertyAsClass_withRealClassForValue() {
MutablePropertySources propertySources = new MutablePropertySources();
propertySources.addFirst(new MockPropertySource().withProperty("some.class", SpecificType.class));
PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources);
assertTrue(resolver.getPropertyAsClass("some.class", SomeType.class).equals(SpecificType.class));
}
@Test(expected=ConversionException.class)
public void getPropertyAsClass_withMismatchedRealClassForValue() {
MutablePropertySources propertySources = new MutablePropertySources();
propertySources.addFirst(new MockPropertySource().withProperty("some.class", Integer.class));
PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources);
resolver.getPropertyAsClass("some.class", SomeType.class);
}
static interface SomeType { }
static class SpecificType implements SomeType { }
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册