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;
|
import org.springframework.core.convert.converter.ConverterRegistry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A specialization of {@link GenericConversionService} configured by default with
|
* A specialization of {@link GenericConversionService} configured by default
|
||||||
* converters appropriate for most environments.
|
* with converters appropriate for most environments.
|
||||||
*
|
*
|
||||||
* <p>Designed for direct instantiation but also exposes the static
|
* <p>Designed for direct instantiation but also exposes the static
|
||||||
* {@link #addDefaultConverters(ConverterRegistry)} utility method for ad hoc use against any
|
* {@link #addDefaultConverters(ConverterRegistry)} utility method for ad-hoc
|
||||||
* {@code ConverterRegistry} instance.
|
* use against any {@code ConverterRegistry} instance.
|
||||||
*
|
*
|
||||||
* @author Chris Beams
|
* @author Chris Beams
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
@@ -39,6 +39,32 @@ import org.springframework.core.convert.converter.ConverterRegistry;
|
|||||||
*/
|
*/
|
||||||
public class DefaultConversionService extends GenericConversionService {
|
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
|
* Create a new {@code DefaultConversionService} with the set of
|
||||||
* {@linkplain DefaultConversionService#addDefaultConverters(ConverterRegistry) default converters}.
|
* {@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.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
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.ConfigurableConversionService;
|
||||||
import org.springframework.core.convert.support.DefaultConversionService;
|
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.PropertyPlaceholderHelper;
|
||||||
import org.springframework.util.SystemPropertyUtils;
|
import org.springframework.util.SystemPropertyUtils;
|
||||||
|
|
||||||
@@ -38,7 +41,7 @@ public abstract class AbstractPropertyResolver implements ConfigurablePropertyRe
|
|||||||
|
|
||||||
protected final Log logger = LogFactory.getLog(getClass());
|
protected final Log logger = LogFactory.getLog(getClass());
|
||||||
|
|
||||||
protected ConfigurableConversionService conversionService = new DefaultConversionService();
|
private volatile ConfigurableConversionService conversionService;
|
||||||
|
|
||||||
private PropertyPlaceholderHelper nonStrictHelper;
|
private PropertyPlaceholderHelper nonStrictHelper;
|
||||||
|
|
||||||
@@ -57,11 +60,21 @@ public abstract class AbstractPropertyResolver implements ConfigurablePropertyRe
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConfigurableConversionService getConversionService() {
|
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
|
@Override
|
||||||
public void setConversionService(ConfigurableConversionService conversionService) {
|
public void setConversionService(ConfigurableConversionService conversionService) {
|
||||||
|
Assert.notNull(conversionService, "ConversionService must not be null");
|
||||||
this.conversionService = conversionService;
|
this.conversionService = conversionService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,6 +85,7 @@ public abstract class AbstractPropertyResolver implements ConfigurablePropertyRe
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void setPlaceholderPrefix(String placeholderPrefix) {
|
public void setPlaceholderPrefix(String placeholderPrefix) {
|
||||||
|
Assert.notNull(placeholderPrefix, "'placeholderPrefix' must not be null");
|
||||||
this.placeholderPrefix = placeholderPrefix;
|
this.placeholderPrefix = placeholderPrefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,6 +96,7 @@ public abstract class AbstractPropertyResolver implements ConfigurablePropertyRe
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void setPlaceholderSuffix(String placeholderSuffix) {
|
public void setPlaceholderSuffix(String placeholderSuffix) {
|
||||||
|
Assert.notNull(placeholderSuffix, "'placeholderSuffix' must not be null");
|
||||||
this.placeholderSuffix = placeholderSuffix;
|
this.placeholderSuffix = placeholderSuffix;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,8 +128,10 @@ public abstract class AbstractPropertyResolver implements ConfigurablePropertyRe
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setRequiredProperties(String... requiredProperties) {
|
public void setRequiredProperties(String... requiredProperties) {
|
||||||
for (String key : requiredProperties) {
|
if (requiredProperties != null) {
|
||||||
this.requiredProperties.add(key);
|
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,
|
* Retrieve the specified property as a raw String,
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ public class PropertySourcesPropertyResolver extends AbstractPropertyResolver {
|
|||||||
value = resolveNestedPlaceholders((String) value);
|
value = resolveNestedPlaceholders((String) value);
|
||||||
}
|
}
|
||||||
logKeyFound(key, propertySource, value);
|
logKeyFound(key, propertySource, value);
|
||||||
return this.conversionService.convert(value, targetValueType);
|
return convertValueIfNecessary(value, targetValueType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,8 +36,6 @@ import org.springframework.util.Assert;
|
|||||||
*/
|
*/
|
||||||
public class StandardTypeConverter implements TypeConverter {
|
public class StandardTypeConverter implements TypeConverter {
|
||||||
|
|
||||||
private static volatile ConversionService defaultConversionService;
|
|
||||||
|
|
||||||
private final ConversionService conversionService;
|
private final ConversionService conversionService;
|
||||||
|
|
||||||
|
|
||||||
@@ -45,10 +43,7 @@ public class StandardTypeConverter implements TypeConverter {
|
|||||||
* Create a StandardTypeConverter for the default ConversionService.
|
* Create a StandardTypeConverter for the default ConversionService.
|
||||||
*/
|
*/
|
||||||
public StandardTypeConverter() {
|
public StandardTypeConverter() {
|
||||||
if (defaultConversionService == null) {
|
this.conversionService = DefaultConversionService.getSharedInstance();
|
||||||
defaultConversionService = new DefaultConversionService();
|
|
||||||
}
|
|
||||||
this.conversionService = defaultConversionService;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ public class BeanPropertyRowMapper<T> implements RowMapper<T> {
|
|||||||
private boolean primitivesDefaultedForNullValue = false;
|
private boolean primitivesDefaultedForNullValue = false;
|
||||||
|
|
||||||
/** ConversionService for binding JDBC values to bean properties */
|
/** ConversionService for binding JDBC values to bean properties */
|
||||||
private ConversionService conversionService = new DefaultConversionService();
|
private ConversionService conversionService = DefaultConversionService.getSharedInstance();
|
||||||
|
|
||||||
/** Map of the fields we provide mapping for */
|
/** Map of the fields we provide mapping for */
|
||||||
private Map<String, PropertyDescriptor> mappedFields;
|
private Map<String, PropertyDescriptor> mappedFields;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2014 the original author or authors.
|
* Copyright 2002-2016 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.
|
||||||
@@ -44,7 +44,7 @@ public class GenericMessageConverter extends SimpleMessageConverter {
|
|||||||
* Create a new instance with a default {@link ConversionService}.
|
* Create a new instance with a default {@link ConversionService}.
|
||||||
*/
|
*/
|
||||||
public GenericMessageConverter() {
|
public GenericMessageConverter() {
|
||||||
this.conversionService = new DefaultConversionService();
|
this.conversionService = DefaultConversionService.getSharedInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
|
|||||||
* values are not expected to contain expressions
|
* values are not expected to contain expressions
|
||||||
*/
|
*/
|
||||||
protected AbstractNamedValueMethodArgumentResolver(ConversionService cs, ConfigurableBeanFactory beanFactory) {
|
protected AbstractNamedValueMethodArgumentResolver(ConversionService cs, ConfigurableBeanFactory beanFactory) {
|
||||||
this.conversionService = (cs != null ? cs : new DefaultConversionService());
|
this.conversionService = (cs != null ? cs : DefaultConversionService.getSharedInstance());
|
||||||
this.configurableBeanFactory = beanFactory;
|
this.configurableBeanFactory = beanFactory;
|
||||||
this.expressionContext = (beanFactory != null ? new BeanExpressionContext(beanFactory, null) : null);
|
this.expressionContext = (beanFactory != null ? new BeanExpressionContext(beanFactory, null) : null);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user