GH-3085 Add Number and Boolean Spel converter

Refactor SpelConverter into an abstract class

Resolves #3085
This commit is contained in:
Oleg Zhurakousky
2025-02-21 15:01:40 +01:00
parent dc164fe3c0
commit 78427b0ef2
2 changed files with 60 additions and 17 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015-2018 the original author or authors.
* Copyright 2015-2025 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.
@@ -16,8 +16,6 @@
package org.springframework.cloud.stream.config;
import java.beans.Introspector;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.BeanDefinition;
@@ -44,6 +42,7 @@ import org.springframework.integration.json.JsonPropertyAccessor;
*
* @author Eric Bottard
* @author Artem Bilan
* @author Oleg Zhurakousky
*/
@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
@@ -61,19 +60,19 @@ public class SpelExpressionConverterConfiguration {
@Bean
public static SpelPropertyAccessorRegistrar spelPropertyAccessorRegistrar() {
return new SpelPropertyAccessorRegistrar()
.add(Introspector
.decapitalize(JsonPropertyAccessor.class.getSimpleName()),
new JsonPropertyAccessor());
.add(new JsonPropertyAccessor());
}
@Bean
@ConfigurationPropertiesBinding
@IntegrationConverter
public Converter<Object, Expression> spelConverter(ConfigurableApplicationContext context) {
public Converter<String, Expression> spelConverter(ConfigurableApplicationContext context) {
SpelConverter converter = new SpelConverter();
ConfigurableConversionService cs = (ConfigurableConversionService) context.getBeanFactory().getConversionService();
if (cs != null) {
cs.addConverter(converter);
cs.addConverter(new NumberToStringSpelConverter());
cs.addConverter(new BooleanToStringSpelConverter());
}
return converter;
}
@@ -83,7 +82,30 @@ public class SpelExpressionConverterConfiguration {
*
* @author Eric Bottard
*/
public static class SpelConverter implements Converter<Object, Expression> {
public static class SpelConverter extends AbstractSpelConverter<String> {
@Override
public Expression convert(String source) {
return this.doConvert(source);
}
}
public static class NumberToStringSpelConverter extends AbstractSpelConverter<Number> {
@Override
public Expression convert(Number source) {
String value = source.toString();
return this.doConvert(value);
}
}
public static class BooleanToStringSpelConverter extends AbstractSpelConverter<Boolean> {
@Override
public Expression convert(Boolean source) {
String value = source.toString();
return this.doConvert(value);
}
}
public static abstract class AbstractSpelConverter<T> implements Converter<T, Expression> {
private SpelExpressionParser parser = new SpelExpressionParser();
@@ -92,12 +114,8 @@ public class SpelExpressionConverterConfiguration {
@Lazy
private EvaluationContext evaluationContext;
@Override
public Expression convert(Object source) {
public Expression doConvert(String source) {
try {
if (!(source instanceof String)) {
source = String.valueOf(source); // see https://github.com/spring-cloud/spring-cloud-stream/issues/2989
}
Expression expression = this.parser.parseExpression((String) source);
if (expression instanceof SpelExpression) {
((SpelExpression) expression)
@@ -110,7 +128,5 @@ public class SpelExpressionConverterConfiguration {
"Could not convert '%s' into a SpEL expression", source), e);
}
}
}
}

View File

@@ -31,6 +31,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.PropertyAccessor;
@@ -47,8 +48,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Artem Bilan
* @author Soby Chacko
*/
@SpringBootTest(classes = SpelExpressionConverterConfigurationTests.Config.class, properties = {
"expression: a.b" })
@SpringBootTest(classes = SpelExpressionConverterConfigurationTests.Config.class)
class SpelExpressionConverterConfigurationTests {
@Autowired
@@ -77,6 +77,12 @@ class SpelExpressionConverterConfigurationTests {
assertThat(propertyAccessors)
.hasAtLeastOneElementOfType(JsonPropertyAccessor.class);
Expression numberExpression = this.pojo.getNumberExpression();
assertThat(numberExpression.getValue()).isEqualTo(5);
Expression booleanExpression = this.pojo.getBooleanExpression();
assertThat(booleanExpression.getValue()).isEqualTo(true);
}
@ConfigurationProperties
@@ -84,6 +90,10 @@ class SpelExpressionConverterConfigurationTests {
private Expression expression;
private Expression numberExpression;
private Expression booleanExpression;
public Expression getExpression() {
return this.expression;
}
@@ -92,11 +102,28 @@ class SpelExpressionConverterConfigurationTests {
this.expression = expression;
}
public Expression getNumberExpression() {
return numberExpression;
}
public void setNumberExpression(Expression numberExpression) {
this.numberExpression = numberExpression;
}
public Expression getBooleanExpression() {
return booleanExpression;
}
public void setBooleanExpression(Expression booleanExpression) {
this.booleanExpression = booleanExpression;
}
}
@Configuration
@EnableAutoConfiguration
@EnableConfigurationProperties(Pojo.class)
@PropertySource("classpath:/application.yml")
public static class Config implements BeanFactoryAware {
private BeanFactory beanFactory;