Can I default a system property for a constructor-arg in a spring config file? - spring

I have a spring config file which includes the following elements:
<context:property-placeholder location="classpath:default.properties"/>
<bean id="theVar" class="java.lang.String">
<constructor-arg value="${varName}"/>
</bean>
"varName" is now moved from the properties file to a system property. It is being added when I start a Maven build:
mvn clean install -DvarName=data
I want to also run my build without specifying varName:
mvn clean install
Is there some way to default varName in my spring config? Though this does not work, a conceptual example of what I am looking for is:
<bean id="theVar" class="java.lang.String">
<constructor-arg value="${varName}" default="theDefaultValue"/>
</bean>

Spring 3.0.x supports a syntax like this:
value="${varName:defaultValue}"
References:
SPR-4785
Changes in version 3.0.0.RC1 (2009-09-25) (PropertyPlaceholderConfigurer supports "${myKey:myDefaultValue}" defaulting syntax)

It turns out that in spring v2.5+, if there is a system property defined, it can be used instead of a property defined in the properties file. You just need to ensure the same name is used and that the 'override' option is enabled.
For example, given:
<!-- my spring config file -->
<context:property-placeholder location="classpath:default.properties" system-properties-mode="OVERRIDE"/>
And:
# default.properties file
theVariable=One
When I execute:
mvn clean install
"One" is picked-up for theVariable. If I execute:
mvn clean install -DtheVariable=Two
"Two" is picked-up instead.

I'm not sure If this will help but if you are annotating classes and want a default value when a system property is not present this is what I currently do:
#Value("#{systemProperties['fee.cc']?:'0.0225'}")
public void setCcFeePercentage(BigDecimal ccFeePercentage) {
this.setCcFeePercentage(ccFeePercentage);
}

It can be done as #sebastien has described but in the configuration file as you want:
<bean id="theVar" class="java.lang.String">
<constructor-arg value="#{systemProperties['varName'] == null ? 'default_value' : systemProperties['varName']}"/>
</bean>
If your varName variable is not present, default value will be set.

Related

How to load a secret.properties file in apacheignite/docker stock image

I used gridgain’s webconsole to create a configuration file for my ignite node (ignite-config.xml). I’d like to see if I can get this running in apache’s docker ignite image (apacheignite/ignite). I’ve created a volume in my compose file that maps to a config folder that houses my ignite-config.xml.
I need to include the secret.properties (that has my jdbc url/username/password) file as well so I put it in the config folder too.
When I do a docker-compose up I get a java.io.FileNotFoundException: class path resource [config/secret.properties] cannot be opened because it does not exist]
This is the part of the xml config that deals with the secret.properties location:
<!-- Load external properties file. -->
<bean id="placeholderConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:secret.properties"/>
</bean>
What do I need to change so that the secret.properties file in the config folder is loaded? Is there a better way to do this?
I do not know how to easily deploy the secret.properties file without going through a full build and deploy, but in order to get past that for testing purposes, you could get rid of the secret.properties and use environment variables instead.
Which might look something like this for a JDBC connection to Postgres:
<!-- Data source beans will be initialized from external properties file. -->
<bean id="dsPostgreSQL_Daifcqkp30zkdj" class="org.postgresql.ds.PGPoolingDataSource">
<property name="url" value="#{systemEnvironment['dsPostgreSQL_Daifcqkp30zkdj_jdbc_url']}"/>
<property name="user" value="#{systemEnvironment['dsPostgreSQL_Daifcqkp30zkdj_jdbc_username']}"/>
<property name="password" value="#{systemEnvironment['dsPostgreSQL_Daifcqkp30zkdj_jdbc_password']}"/>
</bean>
Then, just set your environment variables:
IGNITE_VERSION=2.7.5
CONFIG_URI=https://raw.github.com/some/path/to/your/config.xml
OPTION_LIBS=ignite-zookeeper,ignite-rest-http
EXTERNAL_LIBS=https://github.com/some/path/to/your/jdbc-drivers/postgresql-42.2.6.jar?raw=true
dsPostgreSQL_Daifcqkp30zkdj_jdbc_username=0a9suf09asdfkjwel
dsPostgreSQL_Daifcqkp30zkdj_jdbc_password=8faskdfn94noiasnf09_s09fklajfealk
dsPostgreSQL_Daifcqkp30zkdj_jdbc_url=jdbc:postgresql://<host>:<port>/Daifcqkp30zkdj?ssl=true&sslfactory=org.postgresql.ssl.NonValidatingFactory
Had the same issue, probably didn't resolve it the "correct" way (whatever that is), but resolved it this way for a POC nonetheless:
Create a standalone jar file with only the secrets file
Give it the name dsPostgreSQL_Daifcqkp30zkdj_jdbc.jar or similar
Place the jar file in the libs directory
It seems the classpath is just the contents of all JAR files in the \libs subdir, so oblige it... This would have the advantage of allowing for a signed JAR - I believe - which would (in addition to file system permissions, visibility, etc.) at least ensure it isn't tampered with.

Spring Boot Reading Properties Files Based on classpath arg

I have created a standalone boot.jar that I need to start integrating into our higher environments.
Each environment has a property file that contains database specific connection information. Since this does not live in my boot jar, I would like to somehow add the path to this database.properties file and then read the entries based on key. Used to create a bean like so:
<bean id="propertyLoader" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<value>classpath:application.properties</value>
</property>
but with boot, I am not sure how to do this: But I want to point to this below property example and pull out my values and somehow populate the application.properties values that I hardcoded in dev.
server:/config/database.properties
jdbc.username=TEST
jdbc.password=CHANGEME
Updating my application.properites:
spring.datasource.username='jdbc.username'
spring.datasource.password='jdbc.password'
Something like that do I can parameterize my application.properties file.
SpringBoot offers profiles, which basically allows you to have separate application.properties file for each environment.
You can have something like this:
public interface DataSourceConfig {}
#Component
#Profile("dev")
public DevDataSourceConfig implements DataSourceConfig{}
#Component
#Profile("prod")
public ProdDataSourceConfig implements DataSourceConfig{}
If you have the spring profile "dev" set as active, only the DevDataSourceConfig bean will be instantiated and in Spring Environment the properties that will be injected, will be read from the application-dev.properties file.
Similarly when you have the "prod" profile activated, only the ProdDataSourceConfig will be instantiated and the properties will be loaded from application-prod.properties file.
This allows you to have:
---
application-dev.properties
spring.datasource.username='jdbc.username'
spring.datasource.password='jdbc.password'
---
application-prod.properties
spring.datasource.username='PROD_jdbc.username'
spring.datasource.password='PROD_jdbc.password'
If you want to load the configuration from a custom location on the file system - you can check how to pass the location with command line arguments (docs)
Example:
java -jar boot.jar --spring.config.location=classpath:/database.properties
you already told you can not have property files inside your jar, still there are multiple options.
1> passing a property file for respective env.
java -jar myproject.jar --spring.config.location=classpath:/database.properties
2> pass properties while calling the jar
java -jar app.jar --spring.datasource.username="jdbc.username" --spring.datasource.password="jdbc.password"
Read a lot of other options here `
I would go with option 1, because passing credentials is never advisable in arguements.

where spring defines variable value, which is referred by some xml file

I am trying to understand from where does the value of a variable comes from, when it is referred in Spring xml file.
For example:
<context:property-placeholder location="classpath:/${com.example.deploy.environment}/com.example.config/mysql.properties" ignore-resource-not-found="false" />
Where is the value of com.example.deploy.environment defined? In my project I searched all over, however i couldn't find anywhere where this values is defined.
Any information in understanding this would be of great help.
This value can come from a variety of source:
application.properties file which you can define in PropertyPlaceholderConfigurer bean.
<bean id="mailProperties" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:application.properties" />
</bean>
...
//Inside application.properties
com.example.deploy.environment=prod
You can provide via command-line:
With Maven vm arguments for JVM System property:
mvn package -Dcom.example.deploy.environment=prod
Running Spring Boot Application:
java -jar app.jar --com.example.deploy.environment="prod"
From System Environment variable of the Operating System. You might have to restart after setting environment variable. See below for windows:
Refer this doc and this article for more info.

Where does Spring EL wiring value from

All:
I wonder how to find where does a spEL value located?
Such as :
<property name="jdbcUrl" value="jdbc:sybase:Tds:${brs.dsread}" />
I check all *.properties file in the eclipse project, but there is no definition. Other than those properties file, where else can I look for it?
Thanks
This is not SpEL it's a simple Property Placeholder.
It could be anywhere on the classpath (e.g. in a jar).
Turn on DEBUG logging for org.springframework to figure out where it comes from.

Overriding a few properties for junit test using spring or camel property placeholder in a maven layout

I want to specify only the properties I want to override in a test properties file of the same name in the src/test/resources folder.
A little more detail...
In a maven layout I have a properties file that contains the deployed value to use (eg. input.uri).
src/main/resources/app.properties:
input.uri=jms:topic:in
app.name=foo_bar
This file's properties are loaded into the context.xml file by the property-placeholder:
src/main/resources/META-INF/spring/context.xml:
<context:property-placeholder properties-ref="springProperties"/>
<util:properties id="springProperties" local-override="true" location="classpath:app.properties" />
I have the test properties file with the same name, app.properties, in src/test/resources folder and override the input.uri definition to one that my junit test will use. (note, app.name doesn't change).
src/test/resources/app.properties:
input.uri=seda:in
How would you write the junit test and/or a test context.xml file so that properties are loaded from the src/main/resources/app.properties file, but any properties defined in the src/test/resources/app.properties file override the ones in the src/main/resources/app.properties file? Without it being obvious that you're loading two different files either in the src/main files or src/test junit test files - I want the property placeholder to search the classpath and pick the right values.
You will have to provide a different name though - if both the properties in the main and the test have the same name, the entire properties in one or the other will take effect.
Instead an approach like this has worked for me:
In your src/main/resources/META-INF/spring/context.xml do this:
<context:property-placeholder location="classpath:app.properties" local-override="true" properties-ref="springProperties"/>
<util:properties id="springProperties">
</util:properties>
In a test-context.xml file:
<import resource="classpath:/META-INF/spring/context.xml">
<util:properties id="springProperties"> <!-- or refer to a overriding file -->
<prop key="input.uri">seda.in</prop>
</util:properties>
This will override the properties for you, while maintaining the not overridden values from the original file.

Resources