Search code examples
javaspringspring-el

SpEL @Value with nested condition


I'm using the @Value annotation, and I want it to be a bit more complex now. I have two config values - val1, and val2. I want to inject it as follows: If val1 exists in the configuration, use it. Else, if val2 is true, inject default1. If it's false, inject default2.

I tried something like:

@Value("#{val1 ? val1 : (val2 ? 'default1' : 'default2')}")

But I keep getting:

`EL1008E`: property or filed 'val1' cannot be found on object of type 'org.springframeowrk.beans.factory.config.BeanExpressionContext' - maybe not public or not valid?

When I try other expressions, such as ${val1} or '${val1}' it still does not seem to work.

What's the correct way to do nested conditions in the @Value annotation, or is it too complex?


Solution

  • I have adjusted the expression and written a small test to illustrate the change. In short, use ${some.prop:defaultVal} to define a default value and use ${some.prop:} to define an empty String as a default value. Also, use single quotes ' in a SPEL expression to indicate the String value instead of a reference.

    Play around with the TestPropertySource to verify the outcome. I have added a second test to show that when a default value is not present, Spring might (not always) decide to return the textual representation of the placeholder.

    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.test.context.TestPropertySource;
    import org.springframework.test.context.junit4.SpringRunner;
    
    import static org.assertj.core.api.Assertions.assertThat;
    
    @RunWith(SpringRunner.class)
    @TestPropertySource(properties = {"val1=v1", "val2=v2"})
    public class SomeTest {
    
        @Value("#{ '${val1:}' != '' ? '${val1}' : ('${val2:}' != '' ? 'default1' : 'default2')}")
        private String testVal;
    
        @Value("${nonExistingValue}")
        private String nonExistingValue;
    
        @Test
        public void test() {
            assertThat(testVal).isEqualTo("v1");
        }
    
        @Test
        public void testNonExistingValue() {
            assertThat(nonExistingValue).isEqualTo("${nonExistingValue}");
        }
    }
    

    Although the above expression works, I would highly recommend to use ConfigurationProperties, or a T expression type operator referring to a static method. The current set up might become even less readable when the expressions becomes more complex.