Avoid early ConversionService determination in StandardBeanExpressionResolver

Closes gh-27446
This commit is contained in:
Juergen Hoeller 2021-09-21 17:42:50 +02:00
parent 49d003857d
commit 0dc5d2794f
2 changed files with 23 additions and 10 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2020 the original author or authors. * Copyright 2002-2021 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.
@ -24,6 +24,7 @@ import org.springframework.beans.factory.BeanExpressionException;
import org.springframework.beans.factory.config.BeanExpressionContext; import org.springframework.beans.factory.config.BeanExpressionContext;
import org.springframework.beans.factory.config.BeanExpressionResolver; import org.springframework.beans.factory.config.BeanExpressionResolver;
import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.expression.Expression; import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser; import org.springframework.expression.ExpressionParser;
import org.springframework.expression.ParserContext; import org.springframework.expression.ParserContext;
@ -156,10 +157,10 @@ public class StandardBeanExpressionResolver implements BeanExpressionResolver {
sec.addPropertyAccessor(new EnvironmentAccessor()); sec.addPropertyAccessor(new EnvironmentAccessor());
sec.setBeanResolver(new BeanFactoryResolver(evalContext.getBeanFactory())); sec.setBeanResolver(new BeanFactoryResolver(evalContext.getBeanFactory()));
sec.setTypeLocator(new StandardTypeLocator(evalContext.getBeanFactory().getBeanClassLoader())); sec.setTypeLocator(new StandardTypeLocator(evalContext.getBeanFactory().getBeanClassLoader()));
ConversionService conversionService = evalContext.getBeanFactory().getConversionService(); sec.setTypeConverter(new StandardTypeConverter(() -> {
if (conversionService != null) { ConversionService cs = evalContext.getBeanFactory().getConversionService();
sec.setTypeConverter(new StandardTypeConverter(conversionService)); return (cs != null ? cs : DefaultConversionService.getSharedInstance());
} }));
customizeEvaluationContext(sec); customizeEvaluationContext(sec);
this.evaluationCache.put(evalContext, sec); this.evaluationCache.put(evalContext, sec);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2021 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.
@ -16,6 +16,8 @@
package org.springframework.expression.spel.support; package org.springframework.expression.spel.support;
import java.util.function.Supplier;
import org.springframework.core.convert.ConversionException; import org.springframework.core.convert.ConversionException;
import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.TypeDescriptor;
@ -37,7 +39,7 @@ import org.springframework.util.Assert;
*/ */
public class StandardTypeConverter implements TypeConverter { public class StandardTypeConverter implements TypeConverter {
private final ConversionService conversionService; private final Supplier<ConversionService> conversionService;
/** /**
@ -45,7 +47,7 @@ public class StandardTypeConverter implements TypeConverter {
* @see DefaultConversionService#getSharedInstance() * @see DefaultConversionService#getSharedInstance()
*/ */
public StandardTypeConverter() { public StandardTypeConverter() {
this.conversionService = DefaultConversionService.getSharedInstance(); this.conversionService = DefaultConversionService::getSharedInstance;
} }
/** /**
@ -54,20 +56,30 @@ public class StandardTypeConverter implements TypeConverter {
*/ */
public StandardTypeConverter(ConversionService conversionService) { public StandardTypeConverter(ConversionService conversionService) {
Assert.notNull(conversionService, "ConversionService must not be null"); Assert.notNull(conversionService, "ConversionService must not be null");
this.conversionService = () -> conversionService;
}
/**
* Create a StandardTypeConverter for the given ConversionService.
* @param conversionService a Supplier for the ConversionService to delegate to
* @since 5.3.11
*/
public StandardTypeConverter(Supplier<ConversionService> conversionService) {
Assert.notNull(conversionService, "Supplier must not be null");
this.conversionService = conversionService; this.conversionService = conversionService;
} }
@Override @Override
public boolean canConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType) { public boolean canConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {
return this.conversionService.canConvert(sourceType, targetType); return this.conversionService.get().canConvert(sourceType, targetType);
} }
@Override @Override
@Nullable @Nullable
public Object convertValue(@Nullable Object value, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType) { public Object convertValue(@Nullable Object value, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {
try { try {
return this.conversionService.convert(value, sourceType, targetType); return this.conversionService.get().convert(value, sourceType, targetType);
} }
catch (ConversionException ex) { catch (ConversionException ex) {
throw new SpelEvaluationException(ex, SpelMessage.TYPE_CONVERSION_ERROR, throw new SpelEvaluationException(ex, SpelMessage.TYPE_CONVERSION_ERROR,