99

We are using a PropertyPlaceholderConfigurer to use java properties in our Spring configuration (details here)

eg:

<foo name="port">
  <value>${my.server.port}</value>
</foo>

We would like to add an additional property, but have a distributed system where existing instances could all use a default value. Is there a way to avoid updating all of our properties files, by indicating a default value in the Spring config for when there isn't an overriding property value defined?

Rog
  • 4,075
  • 2
  • 24
  • 35

7 Answers7

288

Spring 3 supports ${my.server.port:defaultValue} syntax.

lexicore
  • 42,748
  • 17
  • 132
  • 221
  • 10
    Just for the reference: [SPR-4785](https://jira.springsource.org/browse/SPR-4785) – cubanacan Jan 11 '13 at 09:37
  • 11
    for me, it always overrides property with default value no matter if property is defined or not. – Ondrej Bozek Nov 01 '13 at 13:55
  • 13
    @OndrejBozek - (sorry to bump an old post) I've run into what could be the same problem, see Spring Framework issue [https://jira.spring.io/browse/SPR-9989]. Where multiple placeholder configurers are involved, default values specified with the ':' notation are only resolved by the first placeholder configurer in the chain. So if the first configurer does not have the property, the property will always be set to the default value, even if configurers further down the chain do have the property. See [http://stackoverflow.com/a/22452984/599609] – tones Jan 15 '15 at 02:42
  • 2
    it seems `${my.server.port:-defaultValue}` also gives the same result, note the "`:-`" as opposed to "`:`". – Captain Man Apr 12 '16 at 13:54
  • 2
    You need to add `` for this to work, or add a `PropertyPlaceholderConfigurer` – shuckc Feb 01 '17 at 11:09
  • how this work in `spring 4`? I have code like `${datasource.portal.acquireIncrement:1}`. its not working. – Darshana Apr 20 '17 at 11:59
35

There is a little known feature, which makes this even better. You can use a configurable default value instead of a hard-coded one, here is an example:

config.properties:

timeout.default=30
timeout.myBean=60

context.xml:

<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="location">
        <value>config.properties</value>
    </property>
</bean>

<bean id="myBean" class="Test">
    <property name="timeout" value="${timeout.myBean:${timeout.default}}" />
</bean>

To use the default while still being able to easily override later, do this in config.properties:

timeout.myBean = ${timeout.default}
Michael Böckling
  • 7,341
  • 6
  • 55
  • 76
29
<foo name="port">
   <value>${my.server.port:8088}</value>
</foo>

should work for you to have 8088 as default port

See also: http://blog.callistaenterprise.se/2011/11/17/configure-your-spring-web-application/

Uberto
  • 2,712
  • 3
  • 25
  • 27
14

Are you looking for the PropertyOverrideConfigurer documented here

http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-factory-overrideconfigurer

The PropertyOverrideConfigurer, another bean factory post-processor, is similar to the PropertyPlaceholderConfigurer, but in contrast to the latter, the original definitions can have default values or no values at all for bean properties. If an overriding Properties file does not have an entry for a certain bean property, the default context definition is used.

skaffman
  • 398,947
  • 96
  • 818
  • 769
JoseK
  • 31,141
  • 14
  • 104
  • 131
  • Could someone explain to me what a `18GerPD8fY4iTbNpC9hHNXNHyrDMampPLA` is? I'm sure everyone else knows and I'm just stupid, but just in case... – Sridhar Sarnobat Sep 08 '17 at 22:04
11

The default value can be followed with a : after the property key, e.g.

<property name="port" value="${my.server.port:8080}" />

Or in java code:

@Value("${my.server.port:8080}")
private String myServerPort;

See:

BTW, the Elvis Operator is only available within Spring Expression Language (SpEL),
e.g.: https://stackoverflow.com/a/37706167/537554

ryenus
  • 15,711
  • 5
  • 56
  • 63
9

http://thiamteck.blogspot.com/2008/04/spring-propertyplaceholderconfigurer.html points out that "local properties" defined on the bean itself will be considered defaults to be overridden by values read from files:

<bean id="propertyConfigurer"class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">  
  <property name="location"><value>my_config.properties</value></property>  
  <property name="properties">  
    <props>  
      <prop key="entry.1">123</prop>  
    </props>  
  </property>  
</bean> 
Robert Tupelo-Schneck
  • 10,047
  • 4
  • 47
  • 58
0

Also i find another solution which work for me. In our legacy spring project we use this method for give our users possibilities to use this own configurations:

<bean id="appUserProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
    <property name="ignoreResourceNotFound" value="false"/>
    <property name="locations">
        <list>
            <value>file:./conf/user.properties</value>
        </list>
    </property>
</bean>

And in our code to access this properties need write something like that:

@Value("#{appUserProperties.userProperty}")
private String userProperty

And if a situation arises when you need to add a new property but right now you don't want to add it in production user config it very fast become a hell when you need to patch all your test contexts or your application will be fail on startup.

To handle this problem you can use the next syntax to add a default value:

@Value("#{appUserProperties.get('userProperty')?:'default value'}")
private String userProperty

It was a real discovery for me.

ikorennoy
  • 220
  • 1
  • 9