Add properties to property placeholder
Solution 1
Not sure if this will help, but what I do in a similar situation is have 2 app.properties files with the same name, one in sec/test/resources and the other in src/main/resources. Now during testing the first is loaded because the test classes are first on the classpath, but when I deploy only the main one is there and so it is loaded.
Solution 2
Does it work if you add the same location
attribute to the context:property-placeholder
defined in testContext.xml
that is in the one defined in applicationContex.xml
? You would also need to add the attribute local-override="true"
to have the properties-ref
override those from under META-INF
.
Edit:
Given your most recent comment, I think that you will need to forgo using the context
namespace and directly use the Spring objects that is uses behind the scenes. Perhaps something like this:
In applicationContext.xml:
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath*:META-INF/spring/*.properties" />
</bean>
In testContext.xml:
<bean id="propertyConfigurerTest" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" parent="propertyConfigurer">
<property name="properties" ref="simulatedTomcatProperties" />
<property name="localOverride" value="true" />
</bean>
<util:properties id="simulatedTomcatProperties">
<prop key="cfmt.applicationBaseUrl">localhost:8080/cfmt</prop>
</util:properties>
I'm guessing you want the local properties to override the properties defined from the classpath resources so I defined localOverride
as true.
Solution 3
If, in your main applicationContext.xml, you specify several property lookups as listed below using a PropertiesFactoryBean, any missed properties files are not loaded, and the last successfully loaded properties file is used. In your case, default.properties (e.g. your test properties file) would be loaded, and because the second file:${catalina}... wouldn't be loaded, your @Value fields would be injected with values specified in default.properties.
Answer taken from here:
<bean id="myProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="ignoreResourceNotFound" value="true" />
<property name="locations">
<list>
<value>classpath:default.properties</value>
<value>file:${catalina.home}/webapps/myProperties.properties</value>
</list>
</property>
</bean>
Solution 4
I solved the problem by splitting up the applicationContext.xml
in two files:
- applicationContext.xml
-- contains the "normal" bean, but NO include of applicationContext-properties.xml
- applicationContext-properties.xml
-- contains the property placeholder config
applicationContext-properties.xml
:
<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="locations" value="classpath*:META-INF/spring/*.properties" />
<property name="ignoreUnresolvablePlaceholders" value="false" />
</bean>
The web application loads both files on startup:
web.xml
:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:META-INF/spring/applicationContext*.xml</param-value>
</context-param>
For my tests I have added a propoperties file: simulatedTomcat.test-properties
that contains all the tomcat properties. note: that this file does not match the pattern used by the properties placeholder configurer of applicationContext-properties.xml
Then I have an properties placeholder configurer for my test that load both kind op properties files (*.properties
and *.test-properties
)
test-context.xml
<import resource="classpath:/META-INF/spring/applicationContext.xml" />
<bean class="org.springframework.web.context.support.ServletContextPropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath*:META-INF/spring/*.properties</value>
<value>classpath*:META-INF/spring/*.test-properties</value>
</list>
</property>
</bean>
Ralph
Updated on July 09, 2022Comments
-
Ralph almost 2 years
I have an application where a property placeholder is used to read properties, configured in
applicationContext.xml
:... <context:property-placeholder location="classpath*:META-INF/spring/*.properties"/> ...
The application runs in an Tomcat and uses the parameter defined in context.xml. The application access this parameter like normal properties (
@Value(${cfma.applicationUrl})
). This worksIn my test cases I do not have this tomcat properties, so I want to add them "manually" to the application context. But also load the normal
applicationContext.xml
testContext.xml:
<import resource="classpath:/META-INF/spring/applicationContext.xml" /> <context:property-placeholder properties-ref="simulatedTomcatProperties"/> <util:properties id="simulatedTomcatProperties"> <prop key="cfmt.applicationBaseUrl">localhost:8080/cfmt</prop> </util:properties>
Now I have two context:property-placeholder and this does not work (of course) – So my question is, who can I extend the properties in the “normal” property-placeholder in my test?
More Explanation of what I need:
- The productive environment (as well as the development environment) defines some properties via Tomcat parameter. Therefore they are not included in any properties file, but nerveless they can be accessed like normal properties (
@Value(${cfma.applicationUrl})
). Moreover there must not be any Fallback, if the properties are not defined in the Tomcat, the application must not start! - In the test cases (that use the spring context) I must some how insert the property (cfma.applicationUrl) so that it can be injected in the annotated variables.
But if I add an second
context:property-placeholder
they are not merged:
@See Comments on https://jira.springsource.org/browse/SPR-4881 -- they explain that behaviour.
When I talk about Tomcat parameter I am talking about somethink like this:
context.xml:
<?xml version="1.0" encoding="UTF-8"?> <Context> <WatchedResource>WEB-INF/web.xml</WatchedResource> <Parameter name="cfmt.applicationBaseUrl" value="http://localhost/demoApp" override="false"/> </Context>
- The productive environment (as well as the development environment) defines some properties via Tomcat parameter. Therefore they are not included in any properties file, but nerveless they can be accessed like normal properties (
-
Ralph almost 13 yearsno unfortunately this does not help. I fare as I understood, the problem is that if I have two
context:property-placeholder
definitons I also have to property place holder, and there are not merged. -
laz almost 13 yearsI would expect that the one in
testContext.xml
would override the one inapplicationContext.xml
if it is loaded 2nd. What is the incorrect behavior that you are seeing? -
Ralph almost 13 yearsIs is not incorrect, it is expected (that it does not work with two context:property-placeholder). The behavior is, that the field annotated @Value(${cfma.applicationUrl}) is not populated in the tests. -- I am searching for a way to "extend" the property-placeholder from the applicationContex.xml in my testContext.xml.
-
Ralph almost 13 yearsBecause my problem belongs to additional properties my workaround is to have an additional properties file for my tests in test/resources (Maven bases project).
-
Ralph almost 13 yearsSo the difference of your suggestion and
<context:property-placeholder location="classpath*:META-INF/spring/*.properties"/>
is not so much. - At least you suggest to have an additional properties file for the tests - right? -
Fil almost 13 yearsExactly. And you could also extend the PropertiesFactoryBean to more closely match your needs; I use it to help me load different config files depending on what I'm doing (e.g. using JNDI for lookups, or using a local H2 database, seeding with DBUnit, etc...)
-
Duncan McGregor almost 13 yearsYes, I do end up duplicating properties in the two files!