Last active
July 10, 2023 12:19
-
-
Save thomasdarimont/7df3f04d3be7acea5dfa to your computer and use it in GitHub Desktop.
How to use custom SpEL functions in @value with Spring Boot
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package demo; | |
import static java.lang.reflect.Modifier.*; | |
import java.util.Arrays; | |
import java.util.Set; | |
import org.springframework.beans.BeansException; | |
import org.springframework.beans.factory.annotation.Value; | |
import org.springframework.beans.factory.config.BeanExpressionResolver; | |
import org.springframework.beans.factory.config.BeanFactoryPostProcessor; | |
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; | |
import org.springframework.boot.SpringApplication; | |
import org.springframework.boot.autoconfigure.SpringBootApplication; | |
import org.springframework.context.annotation.Bean; | |
import org.springframework.context.expression.StandardBeanExpressionResolver; | |
import org.springframework.expression.spel.support.StandardEvaluationContext; | |
import org.springframework.util.ReflectionUtils; | |
import org.springframework.util.StringUtils; | |
@SpringBootApplication | |
public class App { | |
public static void main(String[] args) { | |
System.setProperty("someProperty", "a,b,c,a"); | |
BusinessComponent bc = SpringApplication.run(App.class, args).getBean(BusinessComponent.class); | |
System.out.println(bc); | |
} | |
static class BusinessComponent { | |
// Here we use our custom spel function | |
@Value("#{#csvToSet(systemProperties['someProperty'])}")// | |
Set<String> values; | |
@Override | |
public String toString() { | |
return "BusinessComponent [values=" + values + "]"; | |
} | |
} | |
@Bean | |
CustomSpelFunctionProvider customSpelFunctionProvider() { | |
return new CustomSpelFunctionProvider(CustomSpelFunctions.class); | |
} | |
@Bean | |
BusinessComponent businessComponent() { | |
return new BusinessComponent(); | |
} | |
public interface CustomSpelFunctions { | |
// our custom SpEL function | |
static Set<String> csvToSet(String line) { | |
return StringUtils.commaDelimitedListToSet(line); | |
} | |
} | |
/** | |
* A custom {@link BeanFactoryPostProcessor} that allows to register custom SpEL functions into the evaluation | |
* context. | |
* <p> | |
* We customize the {@link BeanExpressionResolver} used by the {@link ConfigurableListableBeanFactory} for the custom | |
* SpEL function registration. | |
*/ | |
static class CustomSpelFunctionProvider implements BeanFactoryPostProcessor { | |
private final Class<?>[] functionHolders; | |
public CustomSpelFunctionProvider(Class<?>... functionHolders) { | |
this.functionHolders = functionHolders; | |
} | |
@Override | |
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { | |
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver() { | |
@Override | |
protected void customizeEvaluationContext(StandardEvaluationContext evalContext) { | |
Arrays.stream(functionHolders).forEach(cls -> ReflectionUtils.doWithMethods(cls, m -> { | |
ReflectionUtils.makeAccessible(m); | |
evalContext.registerFunction(m.getName(), m); | |
}, m -> isPublic(m.getModifiers()) && isStatic(m.getModifiers()))); | |
} | |
}); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment