property not found with multiple context:property-placeholder - java

I am using spring 3.1 with spring profiles to load the beans. In my app context file, I load the properties like :
<context:property-placeholder order="1" location="classpath*:META-INF/spring/*_${spring.profiles.active}.properties" ignore-unresolvable="true"/>
And then I use the property value to load the data source bean like
<property name="driverClassName" value="${database.driverClassName}"/>
It works fine.
The problem starts when I add a couple of more property placeholders so that properties from some database tables can be loaded.
This uses a properties reference loaded by
<bean id="configFactoryBean"
class="org.springmodules.commons.configuration.CommonsConfigurationFactoryBean">
<constructor-arg ref="globalSystemConfiguration"/>
</bean>
To add to the details, this configFactoryBean uses the datasource to load the properties from the database.
When I do this, I have the following exception:
java.lang.ClassNotFoundException: ${database.driverClassName}
My analysis is that its trying to load the datasource before resolving the property from the first context property placeholder. I may be wrong. Or maybe spring profile variable is not resolved properly.
Can anyone please help me to fix this.
Thanks
Akki

This bug about multiple property placeholders might relate to your problem: https://jira.spring.io/browse/SPR-9989
When using multiple PropertyPlaceholderConfigurer in conjunction with
#Value annotation and default value for placeholders syntax (ie
${key:defaultValue}), only the first PropertyPlaceholderConfigurer is
used. If this configurer does not contain the desired value, it falls
back to #Value default even if the second
PropertyPlaceholderConfigurer contains the value.
Affects Version/s: 3.1.3

Each <context:property-placeholder> creates a new instance of PropertyPlaceholderConfigurer - it gets messy easily. You should have one such thing per application and on application level, not on libraries' one - that makes maintenance much easier.
For more details and a suggestion how to cope with it look here:
http://rostislav-matl.blogspot.cz/2013/06/resolving-properties-with-spring.html

In my application I am using property-placeholder configurer in following way and it works very well. You can try that.
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath*:META-INF/spring/*_${spring.profiles.active}.properties</value>
</list>
</property>
</bean>
I think this should resolve your problem. :)

Since you have suggested hardcoding the path to the configuration file works, try using the profiles attribute on the tag to selectively include the configuration.
<beans profile="profileName">
<context:property-placeholder order="1" location="classpath*:META-INF/spring/hardcoded.properties" ignore-unresolvable="true"/>
</beans>
<beans profile="profileName2">
<context:property-placeholder order="1" location="classpath*:META-INF/spring/hardcoded.properties" ignore-unresolvable="true"/>
</beans>
See this article explaining profiles: http://java.dzone.com/articles/using-spring-profiles-xml

Related

Configure internationalization from application.properties in spring boot

I was wondering if I can configure how spring boot handles internationalization using the application.properties file instead of writing it in code.
For example:
To define a LocaleChangeInterceptor I have to declare a bean like this:
<bean id="localeChangeInterceptor"
class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="lang" />
</bean>
However, a look at the most used properties in the documentation shows only 3 values that can be configured for internationalization:
# INTERNATIONALIZATION (MessageSourceAutoConfiguration)
spring.messages.basename=messages
spring.messages.cache-seconds=-1
spring.messages.encoding=UTF-8
So is there a way to achieve this? is there a convention on how to map this to a properties file?
is there a convention on how to map this to a properties file?
No there isn't. It's only a single bean definition and it's entirely optional, so I would prefer to leave that in Java.

Spring Property Consolidation

I've got a Spring bean:
<bean id="sharedBean" class="com.bean.SharedBean">
<constructor-arg name="app-name" value="#{ config['app.name'] }"/>
</bean>
This bean is defined in a jar and used in two apps that both get deployed to the same tomcat server. I've only got one properties file the apps share and I'd like to keep it that way if possible. You might see the problem - I need two values for app.name (one for each web app).
I need to set the app.name independently in each app. I don't mind hard coding the value in the Java (but don't think I can inject the value in that direction). I know I can introduce another properties file at a different path and override but I'm hoping there is a better way I can accomplish this through Spring that will allow me to maintain only one shared properties file.
Possible solutions, in recommended order:
1 - is there a reason why the shared bean is declared in a separate jar file? Certainly, the bean class can be located there, but why not declare the actual bean inside the individual web apps where it's being used?
2 - if you absolutely need to keep the bean definition in the shared jar you can use bean inheritance; (a) change your bean class to use a property rather than a constructor arg:
<bean id="sharedBean" class="com.bean.SharedBean">
<property name="app-name" value="default"/>
</bean>
(b) in your web app context file:
<bean id="instanceBean" parent="sharedBean">
<property name="app-name" value="app1"/>
</bean>
3 - use a Spring profile; in your shared jar context.xml:
<beans profile="app1">
<bean id="sharedBean" class="com.bean.SharedBean">
<constructor-arg name="app-name" value="app1"/>
</bean>
</beans>
<beans profile="app2">
<bean id="sharedBean" class="com.bean.SharedBean">
<constructor-arg name="app-name" value="app2"/>
</bean>
</beans>
note: <beans profile=... MUST be the last entries in your context file.
Add a context param to each web.xml (changing value as appropriate):
<context-param>
<param-name>spring.profiles.default</param-name>
<param-value>app1</param-value>
</context-param>

metrics-spring configuration via .properties file

I'm trying to configure metrics-spring via configuration file
In my spring.xml I've added
<bean id="propertyPlaceholderConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>
classpath:metrics.properties
</value>
</list>
</property>
<property name="systemPropertiesModeName"
value="SYSTEM_PROPERTIES_MODE_OVERRIDE"/>
<property name="searchSystemEnvironment" value="true"/>
</bean>
filled with something like
metrics.reporter.type=console
and then I'm setting it in the spring config accessing that property via ${metrics.reporter.type}
<metrics:reporter metric-registry="metrics" type="${metrics.reporter.type}" period="1m"/>
During the startup of the web application, spring throws a BeanDefinitionParsingException due to the unresolved variable above
Configuration problem: No ReporterElementParser found for reporter type '${metrics.reporter.type}'
I'm using this configuration method (via properties file) for mongo host and port and it works like a charm.
I'm running in Tomcat7, Spring 4.0.5.RELEASE, metrics framework 3.1.0-SNAPSHOT (I need jersey 2 support) and metrics-spring 3.0.1. I also tried with a self-compiled metrics-spring 3.1.0-SNAPSHOT but doesn't solve my problem.
[EDIT]
Found this issue which explain that SpEL is not supported by the ElementParser.
I'm afraid it isn't possible to use a property placeholder in the type attribute. Spring does not resolve property placeholders or SpEL until the phase after metrics-spring reads the type attribute and parses the reporter element (which is necessary to allow placeholders and bean references to be used in all the other attributes).
A possible solution would be to configure all the reporters you might want to use, and use a placeholder in the enabled attribute:
<metrics:reporter metric-registry="metrics" type="console" period="1m"
enabled="${metrics.reporter.console.enabled}" />
<metrics:reporter metric-registry="metrics" type="slf4j" period="1m"
enabled="${metrics.reporter.slf4j.enabled}" />
And the properties file:
metrics.reporter.console.enabled=true
metrics.reporter.slf4j.enabled=false
I hope this makes sense, I've had a very long week!

Changing scope of many Spring beans during tests

I'm running tests using spring (SpringJUnit4ClassRunner and #ContextConfiguration). The tests are run in parallel.
Some of my beans are singleton, and I would like to change them to be in scope "thread" of the tests. I want each test to have its own instance of the bean.
I've managed to it by having an applicationContext.xml file and a applicationTestContext.xml file which is used for tests.
In the applicationTestContext.xml I define those beans with scope "thread".
The problem with this is that everytime we add a new bean of that type, we'll have to add it to both applicationContext.xml and applicationTestContext.xml which is pretty annoying.
Is there a way to do it with less boilerplate?
Gather up all the beans whose scope you want to customize and put them in a separate bean config file, included from both applicationContext and applicationTestContext, e.g.
<import resource="customScopedBeans.xml"/>
Then use a placeholder for the scope
<bean class="com.Foo" scope="${threadOrSingleton}" />
and declare the property differently in the parent config file.
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="properties">
<value>threadOrSingleton=thread</value>
</property>
</bean>

Spring JMX. Set the default value of #ManagedAtrribute through XML

I'm using Spring 3.0.5
I have a #ManagedResource bean, for some of the #ManagedAttribute methods which I want to set a defaultValue. Instead of setting it to a hardcoded value I want to be able to read it from a property value at load time, since the default changes from environment to environment.
A snippet from my programs applicationContext.xml:
<context:mbean-export default-domain="sampleApp"/>
<bean id="managedBean" class="com.example.sampleBean">
<constructor-arg value="Sample Bean"/>
<constructor-arg value="${sample.property}"/>
</bean>
I believe I have to use the XML configuration to be able to do this, but haven't figured out how to do it yet.
You can add the following to your applicationContext.xml, it should expose the properties you are after:
<context:property-placeholder location="classpath:application.properties"/>
So if the application.properties file you are pointing to above contains a property called sample.property then Spring will use that to inject into your ${sample.property} placeholder.
For more details you can see the Spring reference here.

Categories

Resources