Search code examples
spring-mvcjndipropertyconfigurator

Spring 4.1x, SimpleNamingContextBuilder and @Value("#{environment.xxx}")


Up until now I have been using Spring 4.0.8, and the following worked just fine:

In my unit test, I was putting a value in the jndi environment:

SimpleNamingContextBuilder _simpleNamingContextBuilder =
        new SimpleNamingContextBuilder();
_simpleNamingContextBuilder.bind(
            "java:comp/env/myBoolVar", true);
_simpleNamingContextBuilder.activate();

Then in my class, I access it like this:

@Value("#{environment.myBoolVar}")
private Boolean _myBoolVar = Boolean.FALSE;

I have upgraded to Spring 4.1.2 and this no longer works. The default value, false, is always used, because Spring isn't able to find the value.

If I use the old way of accessing this value:

@Resource(mappedName = "java:comp/env/myBoolVar")

it does work.

I have been scouring SO and the web at large and I have seen tons of information but none has helped me to fix the problem. My understanding is that the Spring Environment has access to all the values @Value does. So I'm not sure what the problem is.


Solution

  • FYI for anyone out there struggling with this. In the end I put the code that added the "myBoolVar" value to the SimpleNamingContextBuilder in a method with a @BeforeClass annotation, and it works fine now.

    Basically what was happening is, upon startup Spring tries to sort out what PropertySources it has, in the StandardServletEnvironment.customizePropertySources() method. When it comes time to look for a jndiProperties, it does the following:

    if(JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
            propertySources.addLast(new JndiPropertySource("jndiProperties"));
        }
    

    And that method, JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable(), does the following:

    try {
                new InitialContext().getEnvironment();
                return true;
            }
            catch (Throwable ex) {
                return false;
            }
    

    Ini my case, the call to getEnvironment() was throwing a NoInitialContextException:

    javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file:  java.naming.factory.initial 
    

    Which prevented Spring from creating a jndiProperties PropertySource, and as such my boolean var was getting lost.

    So I started looking all over the web for why this was happening ... but then found an old article on the Spring Forum saying this put my code in a @BeforeClass block, et voilà.

    I hope this saves someone some pain and suffering at some time on the future.