I'm having trouble injecting JNDI values from my Tomcat into spring java config using the @Value
annotation whereas I have no trouble retreiving the values via the Environment
class. We are using Java 1.7.0_17, Spring 4.0.3, and Tomcat 7.0.52 .
I have in my context.xml
the following variables defined:
<Environment name="USER_NAME" value="initech" type="java.lang.String" />
<Environment name="USER_PASSWORD" value="1n3+3ch!" type="java.lang.String" />
In my Java configuration file I have the following code working:
@Bean
public Foo foo( Environment env ){
return new Foo( env.getProperty("USER_NAME"), env.getProperty("USER_PASSWORD") );
}
When I look into the server log I see:
12:50:45.214 [RMI TCP Connection(3)-127.0.0.1] DEBUG o.s.c.e.PropertySourcesPropertyResolver -> Searching for key 'USER_NAME' in [servletConfigInitParams]
12:50:45.214 [RMI TCP Connection(3)-127.0.0.1] DEBUG o.s.c.e.PropertySourcesPropertyResolver -> Searching for key 'USER_NAME' in [servletContextInitParams]
12:50:45.214 [RMI TCP Connection(3)-127.0.0.1] DEBUG o.s.c.e.PropertySourcesPropertyResolver -> Searching for key 'USER_NAME' in [jndiProperties]
12:50:45.214 [RMI TCP Connection(3)-127.0.0.1] DEBUG o.springframework.jndi.JndiTemplate -> Looking up JNDI object with name [java:comp/env/USER_NAME]
12:50:45.214 [RMI TCP Connection(3)-127.0.0.1] DEBUG o.s.jndi.JndiLocatorDelegate -> Located object with JNDI name [java:comp/env/USER_NAME]
12:50:45.214 [RMI TCP Connection(3)-127.0.0.1] DEBUG o.s.jndi.JndiPropertySource -> JNDI lookup for name [USER_NAME] returned: [initech]
12:50:45.214 [RMI TCP Connection(3)-127.0.0.1] DEBUG o.s.c.e.PropertySourcesPropertyResolver -> Found key 'USER_NAME' in [jndiProperties] with type [String] and value 'initech'
However, I would like to use @Value
annotation to make the code cleaner if at all possible; something along the lines of
@Bean
public Foo foo(
@Value( "#{USER_NAME}" ) String userName,
@Value( "#{USER_PASSWORD}" ) String userPassword
){
return new Foo( userName, userPassword );
}
but this code results in the error:
nested exception is org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 0): Property or field 'USER_NAME' cannot be found on object of type 'org.springframework.beans.factory.config.BeanExpressionContext' - maybe not public?; nested exception is org.springframework.beans.factory.BeanExpressionException: Expression parsing failed; nested exception is org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 0): Property or field 'USER_NAME' cannot be found on object of type 'org.springframework.beans.factory.config.BeanExpressionContext' - maybe not public?; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'oauthTokenRequestClient' defined in class path resource [com/initech/set/gw/api/config/GatewayRepositoryConfig.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [java.net.URI]: : Expression parsing failed; nested exception is org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 0): Property or field 'USER_NAME' cannot be found on object of type 'org.springframework.beans.factory.config.BeanExpressionContext' - maybe not public?; nested exception is org.springframework.beans.factory.BeanExpressionException: Expression parsing failed; nested exception is org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 0): Property or field 'USER_NAME' cannot be found on object of type 'org.springframework.beans.factory.config.BeanExpressionContext' - maybe not public?
org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:747)
org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:462)
I have tried "#{systemEnvironment.USER_NAME}
, "#{systemProperties.USER_NAME}
, "#{jndiProperties.USER_NAME}
, and "#{java:comp/env/USER_NAME}
as well: yet, none of them work.
PS- I've tried to simplify the question so if one of these should have worked let me know because I may have made an error in my posting.
no :) you can use annotations to annotate classes, fields, methods and their arguments. but not in methods, since there is no way, to get method- local variables using reflection in order to process these annotations. Use @Value in your field, and read the value from your method.
Spring @Value annotation is used to assign default values to variables and method arguments. We can read spring environment variables as well as system variables using @Value annotation.
@Value is a Java annotation that is used at the field or method/constructor parameter level and it indicates a default value for the affected argument. It is commonly used for injecting values into configuration variables - which we will show and explain in the next part of the article.
The annotation @Value is used to automatically assign a value from multiple environment such as spring environment, system environment, property files, bean objects, default value etc. The annotation @Value in spring boot is commonly used to inject the configuration values to the spring boot application.
I solved it using the selected answer from the question Java Spring: How to use @Value
annotation to inject an Environment
property?.
So my code looks like:
@Bean
public Foo foo(
@Value( "#{environment.USER_NAME}" ) String userName,
@Value( "#{environment.USER_PASSWORD}" ) String userPassword
){
return new Foo( userName, userPassword );
}
I'm assuming from the content of the most upvoted answer (ie "assuming that you have a PropertySourcesPlaceHolderConfigurer
registered") to that quesiton that this means we are lacking a configured PropertySourcesPlaceHolderConfigurer
.
If you are using Spring 4 you should change
@Value( "#{USER_PASSWORD}" ) String userPassword
To
@Value( "${USER_PASSWORD}" ) String userPassword
Try that and see what happens.
For Spring 3.1+ (tested on 4.2.5.RELEASE), you can use @Value
like this:
@Value("${property.name}")
private String jndiProperty;
But you also need to define a PropertySourcesPlaceholderConfigurer
bean in a static
method and configure a JndiPropertySource
(I have this in an @Configuration
class):
@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer(ConfigurableEnvironment env) {
PropertySourcesPlaceholderConfigurer placeholderConfigurer = new PropertySourcesPlaceholderConfigurer();
JndiPropertySource jndiPropertySource = new JndiPropertySource("java:comp");
env.getPropertySources().addFirst(jndiPropertySource);
return placeholderConfigurer;
}
Note the use of addFirst()
which ensures property values from JNDI take precedence in case of a clash with other property sources, which may or may not be desired, in which case one can use other methods like addLast()
etc.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With