Long story short:
Is there a way to interpret the string resulting from ${my.property}
as a SpEL expression within a @Value
annotation without using converters, e.g. something like @Value("#{${my.property}}
)?
I have an abstract factory (simplified) that lets me build some common objects that are part of the configuration of my system.
@Component
public class Factory {
public Product makeVal(int x) { return new Product(5); }
}
In order to be more flexible, I'd like to let users write SpEL expressions in the app.properties
file, so that the factory can directly be accessed:
my.property = @Factory.makeVal(12)
Now, in the class needing this property, to achieve my goal I wrote the following code.
@Value("#{${my.property}}")
private Product obj;
I thought that ${my.property}
would be be macro-expanded and then evaluated by #{}
as the corresponding SpEL expression, @Factory.makeVal(12)
in the example above. Unfortunately, this wasn't the case, and loading the Spring context resulted in an error saying that it could not convert a string (the property's value ${my.property}
) to the destination type Product
.
Now, I solved this by writing a class implementing Converter<String, Product>
, but it's very convoluted as I need there to programmatically evaluate the string as a SpEL expression by instantiating the ExpressionParser
and so on.
But is there a simpler solution? Is there a single SpEL expression to be put in @Value
annotations that lets me simply evaluate ${my.property}
as a SpEL expression by itself, please?
Maybe it just a matter of replacing @Factory
with factory
in the property value. This test passes for me:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { SpelTest.Config.class })
public class SpelTest
{
@Value("#{${my.property}}")
Product _product;
@Test
public void evaluating_spel_from_property_value() throws Exception
{
Assert.assertEquals(1234, _product.value);
}
@Component
public static class Factory
{
public Product makeVal(int x) { return new Product(x); }
}
public static class Product
{
public final int value;
public Product(final int value) { this.value = value; }
}
@Configuration
@ComponentScan(basePackageClasses = SpelTest.class)
public static class Config
{
@Bean
public Factory factory() { return new Factory(); }
@Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
final PropertySourcesPlaceholderConfigurer psc = new PropertySourcesPlaceholderConfigurer();
final MutablePropertySources sources = new MutablePropertySources();
sources.addFirst(new MockPropertySource()
.withProperty("my.property",
"factory.makeVal(1234)"));
psc.setPropertySources(sources);
return psc;
}
}
}