Shared DefaultConversionService instance for simple fallback purposes
Issue: SPR-14948
(cherry picked from commit 80931b2)
This commit is contained in:
parent
5ca10b1d67
commit
a7ba63d425
|
|
@ -52,6 +52,30 @@ public class DefaultConversionService extends GenericConversionService {
|
|||
private static final boolean streamAvailable = ClassUtils.isPresent(
|
||||
"java.util.stream.Stream", DefaultConversionService.class.getClassLoader());
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -224,6 +241,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,
|
||||
|
|
|
|||
|
|
@ -83,7 +83,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);
|
||||
}
|
||||
|
|
@ -108,8 +108,7 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
|
|||
}
|
||||
|
||||
if (!ClassUtils.isAssignableValue(parameter.getParameterType(), arg)) {
|
||||
arg = this.conversionService.convert(
|
||||
arg, TypeDescriptor.valueOf(arg.getClass()), new TypeDescriptor(parameter));
|
||||
arg = this.conversionService.convert(arg, TypeDescriptor.forObject(arg), new TypeDescriptor(parameter));
|
||||
}
|
||||
|
||||
handleResolvedValue(arg, namedValueInfo.name, parameter, message);
|
||||
|
|
|
|||
Loading…
Reference in New Issue