Set System Property With Spring Configuration File

JavaSpringJunitLog4j

Java Problem Overview


Configuration:
Spring 2.5, Junit 4, Log4j
The log4j file location is specified from a system property

${log.location}

At runtime, system property set with -D java option. All is well.

Problem / What I Need:
At unit test time, system property not set, and file location not resolved.
App uses Spring, would like to simply configure Spring to set the system property.

More Info:
Requirement is for configuration only. Can't introduce new Java code, or entries into IDE. Ideally, one of Spring's property configuration implementations could handle this--I just haven't been able to find the right combination.

This idea is close, but needs to add Java code:
Spring SystemPropertyInitializingBean

Any help out there? Any ideas are appreciated.

Java Solutions


Solution 1 - Java

There was a request in the comments for a Spring 3 example on how to do this.

<bean id="systemPrereqs"
    class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="targetObject" value="#{@systemProperties}" />
    <property name="targetMethod" value="putAll" />
    <property name="arguments">
        <!-- The new Properties -->
        <util:properties>
            <prop key="java.security.auth.login.config">/super/secret/jaas.conf</prop>
        </util:properties>
    </property>
</bean>

Solution 2 - Java

You can achieve that with the combination of two MethodInvokingFactoryBeans

Create an inner bean that accesses System.getProperties and an outer bean that invokes putAll on the properties acquired by the inner bean:

<bean
	class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
	<property
		name="targetObject">
		<!-- System.getProperties() -->
		<bean
			class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
			<property name="targetClass" value="java.lang.System" />
			<property name="targetMethod" value="getProperties" />
		</bean>
	</property>
	<property
		name="targetMethod"
		value="putAll" />
	<property
		name="arguments">
		<!-- The new Properties -->
		<util:properties>
			<prop
				key="my.key">myvalue</prop>
			<prop
				key="my.key2">myvalue2</prop>
			<prop
				key="my.key3">myvalue3</prop>

		</util:properties>
	</property>
</bean>

(You could of course use just one bean and target System.setProperties(), but then you'd be replacing existing properties which is not a good idea.

Anyway, here's my little test method:

public static void main(final String[] args) {

	new ClassPathXmlApplicationContext("classpath:beans.xml");

	System.out.println("my.key: "+System.getProperty("my.key"));
	System.out.println("my.key2: "+System.getProperty("my.key2"));
	System.out.println("my.key3: "+System.getProperty("my.key3"));

	// to test that we're not overwriting existing properties
	System.out.println("java.io.tmpdir: "+System.getProperty("java.io.tmpdir"));
}

And here's the output:

my.key: myvalue
my.key2: myvalue2
my.key3: myvalue3
java.io.tmpdir: C:\DOKUME~1\SEANFL~1\LOKALE~1\Temp\

Solution 3 - Java

Spring Batch has a SystemPropertyInitializer class which can be used to set a system property slightly more concisely, e.g. to force JBoss logging to use slf4j (with Spring JPA):

<bean id="setupJBossLoggingProperty"
    class="org.springframework.batch.support.SystemPropertyInitializer"
  	p:keyName="org.jboss.logging.provider" p:defaultValue="slf4j"/>
  
<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
	depends-on="setupJBossLoggingProperty"

Remember to add the "depends-on" attribute to force the system property to be set first.

Solution 4 - Java

For a more terse approach try:

<beans ... xmlns:p="http://www.springframework.org/schema/p" ...    
    <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean" 
		p:targetObject="#{@systemProperties}" p:targetMethod="setProperty"
		p:arguments="#{{'org.jboss.logging.provider','slf4j'}}"/>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSteveView Question on Stackoverflow
Solution 1 - JavaPatrickView Answer on Stackoverflow
Solution 2 - JavaSean Patrick FloydView Answer on Stackoverflow
Solution 3 - JavapaulcmView Answer on Stackoverflow
Solution 4 - JavaPaul RooneyView Answer on Stackoverflow