spring - <context:property-placeholder> load multiple properties but ignore missing ones - java

I used the following configuration in my applicationContext.xml
<context:property-placeholder location="classpath:system.properties,file:/data/conf/system.properties,file:/data/conf/1033.properties" ignore-unresolvable="true" />
to load some placeholders:
use these properties defined in classpath:system.properties;
if file or properties exist in /data/conf/system.properties, use them instead of above;
if file or properties exist in /data/conf/1033.properties, use them instead of above.
Now Spring started ok if both /data/conf/system.properties and /data/conf/1033.properties exists, but it will throw rg.springframework.beans.factory.BeanInitializationException: Could not load properties; nested exception is java.io.FileNotFoundException: ... if either of them does not exist.
How to tell spring load these properties but ignore missing ones.

You have to add ignore-resource-not-found="true"
<context:property-placeholder location="classpath:system.properties,file:/data/conf/system.properties,file:/data/conf/1033.properties"
ignore-unresolvable="true"
ignore-resource-not-found="true"/>

Related

how to dynamically load the config in java with spring

I'm writing a WebApp back-end with spring in java. in the code there are a lot of magic numbers. is there a way to put this in a config in such a way that any changes in this config will be put in effect without restarting the entire app?
When java process start it loads spring context, once spring context is loaded it only reads properties file once so if you are changing any property you have to restart your app thats good to have way.
OR you can replace java.util.Properties with a PropertiesConfiguration from the Apache Commons Configuration project. It supports automatic reloading, either by detecting when the file changes, or by triggering through JMX.
one more alternate way is to keep all your prop variables in database and refresh your reference cache periodically that way you don't have to restart your app and can change properties on-fly from database.
You can call the configuration file through the below steps:
Use the #Configuration annotation for the class which calls the
config file.
Another annotation to be declared above the class for defining the path to the config file #PropertySource({"URL/PATH_OF_THE_CONFIG_FILE"})
#Value("${PROPERTY_KEY}") annotation above a variable where the value corresponding to the property_key needs to be assigned.
The the following bean in the same configuration invoking class.
#Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
return new PropertySourcesPlaceholderConfigurer();
}
Make sure the #ComponentScan covers the folder where the config file is placed
Here is the way you can configure it
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemalocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<!--To load properties file -->
<bean id="placeholderConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:META-INF/*-config.properties">
</property></bean>
<bean id="createCustomer" class="com.example.Customer">
<property name="propertyToInject" value="${example.propertyNameUnderPropertyFile}">
</beans>
You can also refer it in java file straight away
public class Customer {
#Value("${example.propertyNameUnderPropertyFile}")
private String attr;
}

Spring resolved property file location needs to resolve those properties

I am using Spring version 4.0.6.RELEASE and am trying to have spring read from a properties file and use one of the resolved properties to provide a location to another properties file. My spring.xml file has the following:
<bean id="applicationProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="locations">
<list>
<value>classpath:application.properties</value>
<value>classpath:version.properties</value>
<!- The below file contains the another file location -->
<value>file:${catalina.base}/conf/instance.properties</value>
<value>${another.file.location}</value>
</list>
</property>
<property name="ignoreResourceNotFound" value="true"/>
</bean>
instance.properties contains:
account.id=BlahBlahBlah
another.file.location=file:/Users/beardman/.myapp/local.properties
and /Users/beardman/.myapp/local.properties contains:
magic.number=3
database.endpoint=blah
I keep getting the following warning:
WARN [main] o.s.b.f.c.PropertyPlaceholderConfigurer Could not load properties from ServletContext resource [/${another.file.location}]: Could not open ServletContext resource [/${another.file.location}]
When debugging my code, I can see that the account.id was injected correctly, but I can never get the magic.number or database.endpoint to show up. How can I get spring to use the resolved property from the instance.properties file as the value for the another.file.location?
EDIT: Added property file contents
Spring by default replaces property placeholders with system properties. Since you want to use properties defined in an external file as well, you need to create a PropertyPlaceholderConfigurer
This tag is the shorthand, but you can define PropertyPlaceholderConfigurer as a bean if you need more control. Add this before your applicationProperties bean
<context:property-placeholder location="file:${catalina.base}/conf/instance.properties"/>
Note that properties in the file will override system properties in the default mode. You can specify that system properties are checked first by adding the attribute systemPropertiesMode="override" to the property-placeholder element

How to add external properties file to classpath in jboss 4.2

I want to read an external properties file when launching Jboss 4.2 . I want to add it to the classpath to read it from a WAR file . I have seen different solutions with Jboss 6 using modules, but I haven't seen anything related to JBoss 4.2.
I have included inside 'jboss-service.xml' the following code :
<!-- Bean for reading properties -->
<mbean code="org.jboss.varia.property.SystemPropertiesService"
name="jboss.util:type=Service,name=SystemProperties">
<!-- Load properties from each of the given comma separated URLs -->
<attribute name="URLList">
./conf/path.tmview.properties
</attribute>
</mbean>
In this file I have defined the property :
property-placeholder filepath=/var/tmview_props/tmview/tmview.properties
This property is used in the following bean definition
<bean id="tmviewConfigurerLocation" class="org.springframework.core.io.FileSystemResource">
<constructor-arg value="${property-placeholder-filepath}" />
</bean>
inside an applicationContext.xml . When I launch jboss, the file of properties is read
15:45:29,939 INFO [SystemPropertiesService] Loaded system properties
from: file:/D:/devel/projects/tmview/deployment/jboss-
...ver/tmview/conf/path.tmview.properties
So, the property is read, but I kept obtaining the following exception
2015-03-24 15:45:39,219 ERROR
[org.springframework.web.context.ContextLoader] Context
initialization failed
org.springframework.beans.factory.BeanInitializationException: Could
not load properties; nested exception is
java.io.FileNotFoundException: ${property-placeholder-filepath} (The
system cannot find the file specified)
at
org.springframework.beans.factory.config.PropertyResourceConfigurer.
postProcessBeanFactory(PropertyResourceConfigurer.java:78)
Is there any special way to read the property inside the spring bean ?
In jboss 4 you was able to drop property files in the <jboss_home>/server/<instance>/conf directory and they would be available from the classpath.
Another possibility is add your custom directory to the classpath, to do this see Adding second conf folder to JBoss 5.1.0
Ok . At the end , I solved the problem . It seems the problem was located in reading from application-context.xml .
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>file:${tmview.conf.variables}</value>
</property>
</bean>
I had to add a property placeholder reader . Regarding to jboss, you can read the parameter file either from conf/jboss-service.xml or deploy/properties-receive.xml, but it seems more appropiate to do the reading from the second one .

Can Spring PropertyPlaceholderConfigurer ignore unset properties in a property location path?

I have a Spring-based web application running in a tomcat container and I want to maintain two different configuration files:
src/main/resources/default.properties: contains defaults for development, integration tests and when no other properties are set
.../tomcat/conf/app.properties: has a different content on different environments and should override default.properties
I have a spring configuration that is working fine when the application runs in a tomcat
app-context.xml
<context:property-placeholder
ignore-resource-not-found="true"
ignore-unresolvable="true"
system-properties-mode="OVERRIDE"
location="classpath:default.properties,
file:${catalina.home}/conf/app.properties"/>
But when I try to use this configuration in an integration test, outside of a tomcat container, loading the applicationContext fails:
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:308)
...
Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Invalid bean definition with name 'org.springframework.beans.factory.config.PropertyPlaceholderConfigurer#0' defined in null: Could not resolve placeholder 'catalina.home'
at org.springframework.beans.factory.config.PropertyPlaceholderConfigurer.processProperties(PropertyPlaceholderConfigurer.java:287)
Is there any way to tell Spring to ignore the location file:${catalina.home}/conf/app.properties when the property catalina.home is not set in the current context?
Since you have a context, where some PP values may be unresolved you can try to use a default variant for the property:
file:${catalina.home:}/conf/app.properties
In this case the path prefix is resolved to the empty String if there is no catalina.home property, e.g. in the System.getProperties(), which is the case for Tomcat, I guess.
And after that the ignore-resource-not-found="true" does the stuff.
you can set ignore-resource-not-found to solve this problem.
Try this:
<context:property-placeholder
ignore-resource-not-found="true"
ignore-unresolvable="true"
system-properties-mode="OVERRIDE"
location="classpath:default.properties,
file:${catalina.home}/conf/app.properties"/>
Code snippet from spring-context.xsd:
<xsd:attribute name="ignore-resource-not-found" type="xsd:boolean" default="false">
<xsd:annotation>
<xsd:documentation><![CDATA[
Specifies if failure to find the property resource location should be ignored.
Default is "false", meaning that if there is no file in the location specified
an exception will be raised at runtime.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
What I'd suggest is using spring profiles to enable/disable property files.
When running in tomcat swith on the "tomcat" or "web" profile and put the loading of the app.properties into that profile.

Override properties and system properties in spring xml

in my Spring configuration I have the following line:
<context:property-placeholder
location="/META-INF/spring/global.properties,#{systemProperties['external.propertyFile'] ?: ''}, /WEB-INF/local.properties"
ignore-resource-not-found="true" />
My intention is to have some defaults shipped in global.propertiesand these should be overridable by another external file passed in through external.propertyFile and some properties are kept local by the application itself in local.properties
From what I see in the logs - global.propertiesand local.properties are processed right but the substitution with #{systemProperties ... } doesn't seem to work here.
Any hint's how to fix that or work around it?
Here's the related log from my app (shortened a bit):
Loading properties file from ServletContext resource [/META-/spring/counter.properties]
Loading properties file from ServletContext resource [/#{systemProperties['external.propertyFile'] ?: ''}]
WARN support.PropertySourcesPlaceholderConfigurer: Could not load properties from ServletContext resource [/#{systemProperties['external.propertyFile'] ?: ''}]: Could not open ServletContext resource [/#{systemProperties['external.propertyFile'] ?: ''}]
Loading properties file from ServletContext resource [/WEB-INF/local.properties]
Just a remark:
In other places of the same XML configuration the substitution works fine - eg. with:
<util:properties
id="myProp"
location="#{systemProperties['my.propertyFile'] ?: '/META-INF/spring/my.properties'}"/>
But this time I need a more complex way to handle/merge the actual property values :(
This worked OK for me
<context:property-placeholder
location="/META-INF/spring/global.properties,${external.propertyFile},/WEB-INF/local.properties"
ignore-resource-not-found="true" />

Categories