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.
Related
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.
I am looking how to use the Java default properties value in XML without specifying in application YML or what ever.
This is my java configuration and default I want to use this URL value until providing it from YML file.
#EnableConfigurationProperties
#ConfigurationProperties(prefix = "test.sample")
public #Data class SampleProperties {
private String serverurl ="test.example.com";
}
When I try to use in XML
<property name="serverURL" value="${test.sample.serverurl}" />
Throwing
IllegalArgumentException : Could not resolve placeholder 'test.sample.serverurl' in value "${test.sample.serverurl}"
Your use of the placeholder in XML does not include a default value to use when it is missing
Default values can be provided with a :default-value suffix on the placeholder
<property name="serverURL" value="${test.sample.serverurl:http://localhost}" />
The example is complicated by the : in the default value, simpler ones might be
value="example:default"
value="test.sample.port:8080"
There is a probable duplicate Is there a way to specify a default property value in Spring XML?. Here is a decent tutorial on properties in Spring.
I have used the following ways to get the values from the properties. But I would like to know which one of these is the best to use to follow the coding standard? Also, are there any other ways that we can get the values from the properties file in Spring?
PropertySourcesPlaceholderConfigurer
getEnvironment() from the Spring's Application Context
Spring EL #Value
Along with the other configuration classes (ApplicationConfiguration etc.) I create a class with the annotation #Service and here I have the following fields to access the properties in my file:
#Service
public class Properties (){
#Value("${com.something.user.property}")
private String property;
public String getProperty (){ return this.property; }
}
Then I can autowire the class and get the properties from my properties file
The answer is,
it depends.
If the properties are configuration values,
then configure a propertyConfigurer
(below is an example for a Spring xml configuration file).
<bean id="propertyConfigurer"
class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="ignoreResourceNotFound" value="true" />
<property name="locations">
<list>
<value>classpath:configuration.properties</value>
<value>classpath:configuration.overrides.properties</value>
</list>
</property>
</bean>
When configured this way,
the properties from the last file found override those found earler
(in the locations list).
This allows you to ship the standard configuration.properties file bundled in the war file and store a configuration.overrides.properties at each installation location to account for installation system differences.
Once you have a propertyConfigurer,
annotate your classes using the #Value annotation.
Here is an example:
#Value("${some.configuration.value}")
private String someConfigurationValue;
It is not required to cluster the configuration values into one class,
but doing so makes it easier to find where the values are used.
#Value will be the simple and easy way to use, as it will inject value from property file to your field.
Both the older PropertyPlaceholderConfigurer and the new PropertySourcesPlaceholderConfigurer added in Spring 3.1 resolve ${…} placeholders within bean definition property values and #Value annotations.
unlike getEnvironment
using property-placeholder will not expose the properties to the
Spring Environment – this means that retrieving the value like this
will not work – it will return null
when you are using <context:property-placeholder location="classpath:foo.properties" /> and you use env.getProperty(key); it will always return null.
see this post for the problem using getEnvironment : Expose <property-placeholder> properties to the Spring Environment
Moreover, in Spring Boot you can use #ConfigurationProperties to define your own properties with hierarchical and type-safe in application.properties. and you don't need to put #Value for every field.
#ConfigurationProperties(prefix = "database")
public class Database {
String url;
String username;
String password;
// standard getters and setters
}
in application.properties:
database.url=jdbc:postgresql:/localhost:5432/instance
database.username=foo
database.password=bar
Quote from : properties with spring
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']}")
My problem looks simple but I'm not able to resolve it. I have a properties file which contains configuration details of all environments (dev, qa, prod).
Example config.properties:
dev.maxLength=2000
qa.maxLength=4000
We have a parent Properties file which holds the host name, environment mappings.
Example hosts.properties:
host1=dev
host2=qa
The property name host1 is stored in a bean hostname.
<bean id="hostname"
factory-bean="localhostInetAddress"
factory-method="getHostName"/>
To resolve the config properties name I have to join the strings as follows,
${${**hostname**}.maxLength} which should be resolved as ${dev.maxLength}
I tried using SpEL with no success. I am getting Could not resolve placeholder Exception. How can I concatenate a bean value in property place holder? How are dynamic property names constructed?
Spring version 3.2
To concatenate the values parsed from Spring property placeholders, you need to escape their values using single quoutes ('') and wrap the placeholder expressions by a SpEL expression using #{}.
<bean id="myService" class=""com.services.MyService">
...
<property name="endpointAddress" value="#{'${server}' + ':' + '${port}' + '${endpoint}'}" />
</bean>
where:
server = http://domain.host.com
port = 7777
endpoint = /services/myservice
The result would be:
http://domain.host.com:7777/services/myservice
I solved the issue by changing PropertyPlaceholderConfigurer beans to Properties.
<util:properties/> are accessible in SpEL.
Example:
"#{prop[host+'.'+'maxLength']}"
where host is a string bean.
It would be better to have environment specific properties in a file of its own and use Spring Profiles.
For example, I have four xml files just for db configuration, local.db.xml, dev.db.xml, qa.db.xml and prod.db.xml.
Inside each db.xml, I set the profile to the appropriate value.
My local.db.xml has
<beans profile="db.local" .. >
For starting Tomcat, I specify the VM options as follows
-Dspring.profiles.active=db.local