Spring 3.0 #Value read from property file gettng exception on deployment - java

I am trying to build a spring 3.0 application version 3.1.0.RELEASE , where i want to read from a property file and using the #Value annotation read from it in my Component class. For this the changes i made:
in mvc-dispatcher-servlet.xml:
<context:property-placeholder location="classpath:mediamonitoring.properties"/>
Component class:
#Component
public class SomeHelper {
#Value("${baseUri}")
private String baseUri;
public String getBaseUri() {
return baseUri;
}
public void setBaseUri(String baseUri) {
this.baseUri = baseUri;
}
}
Property:
baseUri:http://localhost:8080/
and i have wired this helper class to a #service class using the #Autowired annotation.
When i build and deploy the application i get the following error:
java.lang.IllegalArgumentException: Could not resolve placeholder 'baseUri'
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:287)
Is there anything which i am missing because i just followed the standard proceedure.
Appreciate any help in advance.
-Vaibhav

Use = instead of : as separator
baseUri=http://localhost:8080/

can't comment, need more rep, so using the asnwer option. check where did u put your mediamonitoring.properties. I mean, check if it's in your classpath

You should escape special characters : and = with \ in value like this:
baseUri:http\://localhost\:8080/
Otherwise parser can't decide where you value ends and where new key starts.
See also Java properties file specs

Assuming you are following the normal practices of having a ContextLoaderListener and a DispatcherServlet make sure that the <context:property-placeholder location="classpath:mediamonitoring.properties"/> is in the correct application-context. It will only operate on beans in the same application-context, not on beans in a parent or child context.

Replace : with = and use # instead of $
#{baseUri}
You can also try to use:
<util:properties id="props"
location="classpath:/yourproperties.properties" />
And than:
#Value("#{props['yourProperty']}")

Related

How do i access -D parameter from Spring Java Config?

i'm looking into migrating my Spring XML config into Java. I'm having some trouble with my PlaceHolderConfigurer.
In XML i have "locations set up as
<property name="locations">
<list>
...
<value>file:////${project.home}/conf/jdbc.properties</value>
</list>
</property>
, where "project.home" is a parameter i've set with "-Dproject.home=...."
Now, i'm not sure how to do this with Java, since i can't just use
new FileSystemResource("file:////${project.home}/conf/jdbc.properties"),
So, if i want to use PropertySourcesPlaceholderConfigurer.setLocations with a system.property, how do i do that? Pointers appreciated.
A combination of context:property-placeholder and #Value annotation can be used for injecting a set of properties into Spring Beans easily.
Here is the 3-step procedure to accomplish this:
Step 1: Define all the required properties inside a 'key=value' type file
application.properties
Step 2: Specify the location of application.properties file in the bean config, using property-placeholder
Step 3: Use #Value annotation in Java program to fetch properties.
Here are the code snippets for a working example:
Step 1: Define properties in 'key=value' format
# File name: application.properties
db.schema=my_schema
db.host=abc.xyz.com:3306
db.table=my_table
Step 2: Mention the location of properties file using property-placeholder
<beans xmlns="http://www.springframework.org/schema/beans" ...>
<context:property-placeholder location="classpath:application.properties"/>
<!-- other content -->
</beans>
Step 3: Fetch properties using #Value annotation
package com.example.demo;
import org.springframework.beans.factory.annotation.Value;
public class MyProgram {
#Value("${db.host}")
private String dbHost;
#Value("${db.schema}")
private String dbSchema;
#Value("${db.table}")
private String dbTable;
#Override
public void showConfig() {
System.out.println("DB Host = " + dbSchema);
System.out.println("DB Schema = " + dbSchema);
System.out.println("DB Table = " + dbSchema);
}
}
Output of call to showConfig()
DB Host = abc.xyz.com:3306
DB Schema = my_schema
DB Table = my_table
More information:
https://memorynotfound.com/load-properties-spring-property-placeholder/
https://memorynotfound.com/loading-property-system-property-spring-value/
https://mkyong.com/spring/spring-propertysources-example/
System.getProperty will give you the property set using -D java option
Since you are attempting to call PropertySourcesPlaceholderConfigurer.setLocations() with custom locations you probably should use #PropertySource annotation.
#Configuration
#PropertySource(value="file://#{systemProperties['project.home']}/conf/jdbc.properties")
public class MyConfig {
}
You can also configure the PropertySourcesPlaceholderConfigurer bean if you need more fine grained control e.g. if your location uses patterns. See this answer for more details.

from Spring context to Spring annotation

I'm moving my project package from Spring xml file configuration to class annotation configuration.
Im stuck with a bean instantiation failed on a bean defined in a another context xml file.
This is the definition :
<bean id="mglsChecker" class="DefaultMglsAdapter" destroy-method="close">
<constructor-arg value="${mgls.server.address}"/>
<constructor-arg value="${mgls.fname}"/>
<constructor-arg value="${mgls.lcount}"/>
</bean>
the mglsChecker class is defined in an infrastucture package common to the entire "solution".
The issue is that the variables "${}" are not defined so now this class is not instantiated.
I dont understand how it works when my project is xml file configured.
In the original applicationContext.xml I dont see any references to this mglsChecker context file.
Any help where should i look into ? what am i missing ?
thanks,
You can use
#Configuration
class YourConfig {
// you usually don't need to explicitly give the bean name
// if you don't, Spring gives it the config's method name
#Bean(name = "mglsChecker", destroyMethod = "close")
MglsAdapter mglsChecker(#Value("${mgls.server.address}") String address,
#Value("${mgls.fname}") String fname,
#Value("${mgls.lcount}") long lcount) {
return new DefaultMglsAdapter(address, fname, lcount);
}
}
Personally, I prefer creating #Component classes, but for that you need to be able to edit the DefaultMglsAdapter class.
#Component
class DefaultMglsAdapter implements MglsAdapter {
// fields to hold the configs
DefaultMglsAdapter(#Value("${mgls.server.address}") String address,
#Value("${mgls.fname}") String fname,
#Value("${mgls.lcount}") long lcount) {
// set fields
}
#PreDestroy
void close() {
// cleanup
}
}
EDIT: incorporated Andreas' correction :)
Load the properties in the java file via
#Configuration
#PropertySource("classpath:foo.properties")
public class DefaultMglsAdapter{
//...
}
Inject the properties via
#Value( "${mgls.server.address}" )
private String serverAddress;
The variables which are mentioned with "${}" syntax are key/place-holders of properties.
Please search or find such key from *.properties or *.config or *.xml or any such custom properties files. If you find any such properties file then specify classpath or location of that file where you want to configure it as given below:
By XML:
<context:property-placeholder location="classpath:path/to/PropertiesFile"/>
By Annotation:
#Configuration
#PropertySource("classpath:path/to/PropertiesFile")
#Value("${Property}")
Thanks and Regards.

Spring - #Value returns null

I have a properties file under /src/main/resources/ and I want to load data from it using Spring.
In my Spring-context.xml I have this :
<context:property-placeholder location="classpath:UserUtil.properties" />
and also have <context:component-scan base-package="com.myApp" />
and in my class I load it like :
#Value("${injectMeThis}")
private String injectMeThis;
but the value is always null
EDIT:
to check if the value, I use this :
System.out.println(new myClass().getInjectMeThis());
System.out.println(new myClass().getInjectMeThis());
Spring will only parse #Value annotations on beans it knows. The code you use creates an instance of the class outside the scope of Spring and as such Spring will do nothing with it.
Assuming you have setup your application context correctly a #Value cannot be null as that will stop the correct startup of your application.
Your XML file contains a <context:component-scan /> assuming myClass is part of that package the easiest solution is to add #Component to myClass and then retrieve the instance from the context instead of creating a new instance.
In your class, add class level annotation #PropertySource("UserUtil.properties"). This should solve the problem.

How to achieve conditional resource import in a Spring XML context?

What I would like to achieve is the ability to "dynamically" (i.e. based on a property defined in a configuration file) enable/disable the importing of a child Spring XML context.
I imagine something like:
<import condition="some.property.name" resource="some-context.xml"/>
Where the property is resolved (to a boolean) and when true the context is imported, otherwise it isn't.
Some of my research so far:
Writing a custom NamespaceHandler (and related classes) so I can register my own custom element in my own namespace. For example: <myns:import condition="some.property.name" resource="some-context.xml"/>
The problem with this approach is that I do not want to replicate the entire resource importing logic from Spring and it isn't obvious to me what I need to delegate to to do this.
Overriding DefaultBeanDefinitionDocumentReader to extend the behaviour of the "import" element parsing and interpretation (which happens there in the importBeanDefinitionResource method). However I'm not sure where I can register this extension.
Prior to Spring 4, the closest you can get using standard Spring components is:
<import resource="Whatever-${yyzzy}.xml"/>
where ${xyzzy} interpolates a property from the system properties. (I use a hacky custom version of the context loader class that adds properties from other places to the system properties object before starting the loading process.)
But you can also get away with importing lots of unnecessary stuff ... and use various tricks to only cause the necessary beans to be instantiated. These tricks include:
placeholder and property substitution
selecting different beans using the new Spring expression language,
bean aliases with placeholders in the target name,
lazy bean initialization, and
smart bean factories.
This is now completely possible, using Spring 4.
In your main application content file
<bean class="com.example.MyConditionalConfiguration"/>
And the MyConditionalConfiguration looks like
#Configuration
#Conditional(MyConditionalConfiguration.Condition.class)
#ImportResource("/com/example/context-fragment.xml")
public class MyConditionalConfiguration {
static class Condition implements ConfigurationCondition {
#Override
public ConfigurationPhase getConfigurationPhase() {
return ConfigurationPhase.PARSE_CONFIGURATION;
}
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// only load context-fragment.xml if the system property is defined
return System.getProperty("com.example.context-fragment") != null;
}
}
}
And then finally, you put the bean definitions you want included in the /com/example/context-fragment.xml
See the JavaDoc for #Conditional
As mentioned earlier, this can be easily accomplished with profiles if you're using Spring 3.1+
<!-- default configuration - will be loaded if no profile is specified -->
<!-- This will only work if it's put at the end of the configuration file -->
<!-- so no bean definitions after that -->
<beans profile="default">
<import resource="classpath:default.xml" />
</beans>
<!-- some other profile -->
<beans profile="otherProfile">
<import resource="classpath:other-profile.xml" />
</beans>
otherProfile can be easily activated with e.g.
mvn install -Dspring.profiles.active=otherProfile
if you're using different profiles in tests, just add -DforkMode=never to make sure that the tests will run inside same VM, therefore the param spring.profiles.active wont be lost
With Spring 3.1.x you can use bean profiles to achieve conditional resource import and bean instantiation. This is of course of no help if you are using an earlier version :)
For the record, Robert Maldon explains how to accomplish conditional definition of beans in this post: http://robertmaldon.blogspot.com/2007/04/conditionally-defining-spring-beans.html. It is a bit long to copy it here (besides, I don't think I should copy-paste his article anyway).
The end result with this approach, adapted for your example, is:
<condbean:cond test="${some.property.name}">
<import resource="some-context.xml"/>
</condbean:cond>
It is certainly not so simple as Stephen C's solution, but it is much more poweful.
Another one to consider for Spring 3.0:
<alias name="Whatever" alias=""Whatever-${yyzzy}" />
where ${xyzzy} interpolates a property from the system properties.
Another option is to have your app load a modules-config.xml file that is located in the /conf folder and edit it during the install/config phase to uncomment the modules you want loaded.
This is the solution I'm using with a web application that serves as a container for different integration modules. The web application is distributed with all the different integration modules. A modules-config.xml is placed in tomcat's /conf folder and the conf folder is added to the classpath (via catalina.properties/common.loader property). My web app webapp-config.xml has a <import resource="classpath:/modules-config.xml"/> to get it loaded.
You can override contextInitialized(javax.servlet.ServletContextEvent event) in your own ContextLoaderListener and set required System property before super.contextInitialized(event) called like this
package com.mypackage;
import org.springframework.web.context.ContextLoaderListener;
public class MyContextLoaderListener extends ContextLoaderListener {
public void contextInitialized(javax.servlet.ServletContextEvent event) {
System.setProperty("xyz", "import-file-name.xml");
super.contextInitialized(event);
}
}
And than replace ContextLoaderListener to MyContextLoaderListener in your web.xml
<listener>
<listener-class>com.mypackage.MyContextLoaderListener</listener-class>
</listener>
Now you can use in your spring.xml
<import resource="${xyz}" />
I hope this will help.

Injecting property values via Spring by Environment

I have a Property File like this:
frame.server.dev=mark.is.cool
frame.server.test=chris.is.cool
frame.server.qa=mitch.is.cool
frame.server.prod=cory.is.cool
I need to inject the correct value based on the environment. Since we have one ear file that we move from environment to environment, I need to do something like this:
<util:properties id="props" location="classpath:ILog-application.properties"/>
and then:
#Value ("props.frame.server.#{systemProperties.the.environment}")
private String server;
However, I cannot get systemProperties to work, nor can I get it to inject anything after a constant. Any help?
It should be
#Value ("#{props['frame.server.' + systemProperties['the.environment']]}")

Categories