Shared DefaultConversionService instance for simple fallback purposes
Issue: SPR-14948
This commit is contained in:
@@ -25,12 +25,12 @@ import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.converter.ConverterRegistry;
|
||||
|
||||
/**
|
||||
* A specialization of {@link GenericConversionService} configured by default with
|
||||
* converters appropriate for most environments.
|
||||
* A specialization of {@link GenericConversionService} configured by default
|
||||
* with converters appropriate for most environments.
|
||||
*
|
||||
* <p>Designed for direct instantiation but also exposes the static
|
||||
* {@link #addDefaultConverters(ConverterRegistry)} utility method for ad hoc use against any
|
||||
* {@code ConverterRegistry} instance.
|
||||
* {@link #addDefaultConverters(ConverterRegistry)} utility method for ad-hoc
|
||||
* use against any {@code ConverterRegistry} instance.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
@@ -39,6 +39,32 @@ import org.springframework.core.convert.converter.ConverterRegistry;
|
||||
*/
|
||||
public class DefaultConversionService extends GenericConversionService {
|
||||
|
||||
private static volatile DefaultConversionService sharedInstance;
|
||||
|
||||
|
||||
/**
|
||||
* Return a shared default {@code ConversionService} instance,
|
||||
* lazily building it once needed.
|
||||
* <p><b>NOTE:</b> We highly recommend constructing individual
|
||||
* {@code ConversionService} instances for customization purposes.
|
||||
* This accessor is only meant as a fallback for code paths which
|
||||
* need simple type coercion but cannot access a longer-lived
|
||||
* {@code ConversionService} instance any other way.
|
||||
* @return the shared {@code ConversionService} instance (never {@code null})
|
||||
* @since 4.3.5
|
||||
*/
|
||||
public static ConversionService getSharedInstance() {
|
||||
if (sharedInstance == null) {
|
||||
synchronized (DefaultConversionService.class) {
|
||||
if (sharedInstance == null) {
|
||||
sharedInstance = new DefaultConversionService();
|
||||
}
|
||||
}
|
||||
}
|
||||
return sharedInstance;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new {@code DefaultConversionService} with the set of
|
||||
* {@linkplain DefaultConversionService#addDefaultConverters(ConverterRegistry) default converters}.
|
||||
|
||||
@@ -22,8 +22,11 @@ import java.util.Set;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.support.ConfigurableConversionService;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.PropertyPlaceholderHelper;
|
||||
import org.springframework.util.SystemPropertyUtils;
|
||||
|
||||
@@ -38,7 +41,7 @@ public abstract class AbstractPropertyResolver implements ConfigurablePropertyRe
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
protected ConfigurableConversionService conversionService = new DefaultConversionService();
|
||||
private volatile ConfigurableConversionService conversionService;
|
||||
|
||||
private PropertyPlaceholderHelper nonStrictHelper;
|
||||
|
||||
@@ -57,11 +60,21 @@ public abstract class AbstractPropertyResolver implements ConfigurablePropertyRe
|
||||
|
||||
@Override
|
||||
public ConfigurableConversionService getConversionService() {
|
||||
return this.conversionService;
|
||||
// Need to provide an independent DefaultConversionService, not the
|
||||
// shared DefaultConversionService used by PropertySourcesPropertyResolver.
|
||||
if (this.conversionService == null) {
|
||||
synchronized (this) {
|
||||
if (this.conversionService == null) {
|
||||
this.conversionService = new DefaultConversionService();
|
||||
}
|
||||
}
|
||||
}
|
||||
return conversionService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setConversionService(ConfigurableConversionService conversionService) {
|
||||
Assert.notNull(conversionService, "ConversionService must not be null");
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
@@ -72,6 +85,7 @@ public abstract class AbstractPropertyResolver implements ConfigurablePropertyRe
|
||||
*/
|
||||
@Override
|
||||
public void setPlaceholderPrefix(String placeholderPrefix) {
|
||||
Assert.notNull(placeholderPrefix, "'placeholderPrefix' must not be null");
|
||||
this.placeholderPrefix = placeholderPrefix;
|
||||
}
|
||||
|
||||
@@ -82,6 +96,7 @@ public abstract class AbstractPropertyResolver implements ConfigurablePropertyRe
|
||||
*/
|
||||
@Override
|
||||
public void setPlaceholderSuffix(String placeholderSuffix) {
|
||||
Assert.notNull(placeholderSuffix, "'placeholderSuffix' must not be null");
|
||||
this.placeholderSuffix = placeholderSuffix;
|
||||
}
|
||||
|
||||
@@ -113,8 +128,10 @@ public abstract class AbstractPropertyResolver implements ConfigurablePropertyRe
|
||||
|
||||
@Override
|
||||
public void setRequiredProperties(String... requiredProperties) {
|
||||
for (String key : requiredProperties) {
|
||||
this.requiredProperties.add(key);
|
||||
if (requiredProperties != null) {
|
||||
for (String key : requiredProperties) {
|
||||
this.requiredProperties.add(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,6 +235,31 @@ public abstract class AbstractPropertyResolver implements ConfigurablePropertyRe
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given value to the specified target type, if necessary.
|
||||
* @param value the original property value
|
||||
* @param targetType the specified target type for property retrieval
|
||||
* @return the converted value, or the original value if no conversion
|
||||
* is necessary
|
||||
* @since 4.3.5
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <T> T convertValueIfNecessary(Object value, Class<T> targetType) {
|
||||
if (targetType == null) {
|
||||
return (T) value;
|
||||
}
|
||||
ConversionService csToUse = this.conversionService;
|
||||
if (csToUse == null) {
|
||||
// Avoid initialization of shared DefaultConversionService if
|
||||
// no standard type conversion is needed in the first place...
|
||||
if (ClassUtils.isAssignableValue(targetType, value)) {
|
||||
return (T) value;
|
||||
}
|
||||
csToUse = DefaultConversionService.getSharedInstance();
|
||||
}
|
||||
return csToUse.convert(value, targetType);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the specified property as a raw String,
|
||||
|
||||
@@ -80,7 +80,7 @@ public class PropertySourcesPropertyResolver extends AbstractPropertyResolver {
|
||||
value = resolveNestedPlaceholders((String) value);
|
||||
}
|
||||
logKeyFound(key, propertySource, value);
|
||||
return this.conversionService.convert(value, targetValueType);
|
||||
return convertValueIfNecessary(value, targetValueType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user