Shared DefaultConversionService instance for simple fallback purposes
Issue: SPR-14948
This commit is contained in:
parent
34c6c9ffc2
commit
80931b211c
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,8 +36,6 @@ import org.springframework.util.Assert;
|
|||
*/
|
||||
public class StandardTypeConverter implements TypeConverter {
|
||||
|
||||
private static volatile ConversionService defaultConversionService;
|
||||
|
||||
private final ConversionService conversionService;
|
||||
|
||||
|
||||
|
@ -45,10 +43,7 @@ public class StandardTypeConverter implements TypeConverter {
|
|||
* Create a StandardTypeConverter for the default ConversionService.
|
||||
*/
|
||||
public StandardTypeConverter() {
|
||||
if (defaultConversionService == null) {
|
||||
defaultConversionService = new DefaultConversionService();
|
||||
}
|
||||
this.conversionService = defaultConversionService;
|
||||
this.conversionService = DefaultConversionService.getSharedInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -88,7 +88,7 @@ public class BeanPropertyRowMapper<T> implements RowMapper<T> {
|
|||
private boolean primitivesDefaultedForNullValue = false;
|
||||
|
||||
/** 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 */
|
||||
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");
|
||||
* 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}.
|
||||
*/
|
||||
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
|
||||
*/
|
||||
protected AbstractNamedValueMethodArgumentResolver(ConversionService cs, ConfigurableBeanFactory beanFactory) {
|
||||
this.conversionService = (cs != null ? cs : new DefaultConversionService());
|
||||
this.conversionService = (cs != null ? cs : DefaultConversionService.getSharedInstance());
|
||||
this.configurableBeanFactory = beanFactory;
|
||||
this.expressionContext = (beanFactory != null ? new BeanExpressionContext(beanFactory, null) : null);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue