Spring boot - Setting configration property thru program arguments - spring

I have a spring boot application and the setting file with the below annotation.
#ConfigurationProperties("test.prop")
public class TestPropSettings {
private String name;
}
The following property in the application.properties set this value.
test.prop.name=XYZ
But, I would like to pass thru program arguments without having the property file.
Tried with,
-Dtest.prop.name=XYZ in eclipse program arguments. But, it does not work. Is there any other way?
Thanks

If you start your jar directly, you can override the property like this:
java -jar your-app.jar --test.prop.name=XYZ
In Eclipse you also need to pass --test.prop.name=XYZ in you program arguments.

Related

application.properties value is not being evaluated correctly across platforms

In my spring boot batch (2.7.3) application.properties file I have:
rs.input.path=/opt/ingestiondata/rs
Afterthat, when I do a mvn clean install on my windows machine, I get the jar file in my target folder. When I try to do java -jar myjar.jar on my local windows command prompt, it give (as expected, as there is no such path) exception - java.nio.file.NoSuchFileException: \opt\ingestiondata\rs
Then I move the same jar file to the linux box there when I do java -jar myjar.jar my key rs.input.path get evaluated to a windows path - c:\users\ajay\some\dir.
What can be wrong here? As I am using the same jar. Its odd but its what happening since last couple of hours. Tried and verified killall java etc etc and now running out of options. Any pointers/help will be greatly appreciated. Must be something trivial and something horrible I am expecting.
Update:
As asked by Abhijit, this is how this is being used.
#Value("${rs.input.path}")
private String inputPath;
#Bean
ItemReader<File> myReader() throws IOException {
List<File> files = Files.walk(Paths.get(inputPath))
.filter(Files::isRegularFile)
.map(Path::toFile)
.collect(Collectors.toList());
return new IteratorItemReader<>(files);
}
I don't think in a spring application,
for any property,
there can't be multiple values;
unless you are using multiple profile specific 'application.properties' files which are specific to each environment.
Option 1:
"""
Check where your property is residing:
'rs.annual.path=/your/linux/path'
Suppose, let's assume it's inside
application-dev.properties
So, you need to select "dev" as Spring profile.
Try running the jar again, by pass passing profile.
(Spring_Property)
java -jar myjar.jar --spring.profiles.active=dev
(Vm_Argument)
2.java -jar -Dspring.profiles.active=dev myjar.jar
"""
Option 2:
"""
Since you are running your jar file inside linux.
Try passing path directly as argument.
(Spring_Property)
java -jar myjar.jar --rs.annual.path=/your/linux/path
You can pass the property as argument. So the Argument-property will taken precedence over Application-property.
"""

java jar -D option passing multiple external config files

I have two configuration files that have to be read using spring boot application, however, only the first configuration property file is resolved (external_application.properties) , later one (queries_config.properties) is not getting detected any issue in passing in the command line.
java -Dexternal.app.properties=file:external_application.properties -Dqueries.config.properties=file:queries_config.properties -jar testsnapshot.jar
If you are using spring boot so you can use
java
-Dspring.config.location=file:external_application.properties,file:queries_config.properties
source
I did like below which resolved over all problem..
java -Dspring.config.location=classpath:file:///C:\Users\configfiles\ -jar testsnapshot.jar
secondly to lookup for external config
#Component
#PropertySource(value = "${spring.config.location}queries_config-${spring.profiles.active}.properties")
#ConfigurationProperties("query")
public class QueriesConfig {
}
#Component
#PropertySource(value = "${spring.config.location}external_application-${spring.profiles.active}.properties")
#ConfigurationProperties("query")
public class ExternalConfig {
}

Externalize password in Spring Boot properties file

i have application.properties file
which has
spring.profiles.active=local
and i have application-local.properties which has many fields including
api.password = password123
As you can see i have hard coded password123 in properties file.
Suppose i am on windows and i have app.properties file on windows which has
api.password = password123
And i want to read api.password in spring boot properties file through app.properties
How can i achieve it ?
Startup parameters
If you want to read properties from a non-standard location, you can start your application with --spring.config.location or with --spring.config.additional-location parameters.
$ java -jar app.jar --spring.config.location=file:./app.properties
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-application-property-files
#PropertySource
If you don't control startup parameters, you can use #PropertySource annotation.
Simply annotate your main class (or any other configuration):
#PropertySource("file:.app.properties")
You can set ignoreResourceNotFound=true, so the application will start, even if the file is not there.
https://docs.spring.io/spring/docs/5.1.9.RELEASE/javadoc-api/org/springframework/context/annotation/PropertySource.html
Read the documentation
There are literally 17 ways to pass properties to a Spring-Boot application.
I suggest, you get familiar with the convention, as it is crucial to understand which file takes a precedence:
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config
Probably you can use --spring.config.location like below
$ java -jar myApp.jar --spring.config.location=file:/directoryof file/app.properties
i used jasypt : https://github.com/ulisesbocchio/jasypt-spring-boot
to encrypt the password, then you supply a decryption string (jasypt.encryptor.password) as startup parameter. That way no useabel password is in the configuration and on the git-repos.....

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.

Running Spring Batch jobs from the command line

I don't know how to call a Job defined in Spring Batch using CommandLineJobRunner, documentation details are not enough for me.
I've followed the Spring Batch official guide to write Jobs in Spring Batch using Java annotations e.g. #EnableBatchProcessing because I wanted to avoid XML configuration files for the description of the job, the steps, etc.
So far I have:
a configuration class (com.package.bla.bla.ClassContainingTheBatchConfiguration see below) where I've put all the stuff defining ItemReader, ItemProcessor, ItemWriter, Job, and Step (with return jobs.get("nameOfTheJob") see below) using a #Bean annotaion.
a class with a main method with SpringApplication.run(...) and and annotation with #ImportResource("classpath:META-INF/spring/applicationContext.xml") to import some beans I need when processing the data in the Job.
On the Maven side I am currently using some plugins:
maven-jar-plugin specifying <addClasspath>true</addClasspath> and the class containing the main method in the tag <mainClass>
maven-assembly-plugin because I would like a unique executable jar containing all the stuff in the dependencies, I am using <phase>package</package> to be able to build the jar in the package phase, I am also using <goal>single</goal> to be able to properly build the jar using the assembly
maven-compiler-plugin specifying I am using Java 1.7
I think I've configured all the things I need to configure, however after having a Maven BUILD SUCCESS I am not able to run the job from the command line:
java -cp ./target/JAR_FILE_NAME.jar org.springframework.batch.core.launch.support.CommandLineJobRunner com.package.bla.bla.ClassContainingTheBatchConfiguration nameOfTheJob
Is throwing IOException due to the java.io.FileNotFoundException regarding com.package.bla.bla.ClassContainingTheBatchConfiguration. How should I specify the parameters in the command line in order to get the Job executed?
If you are already using SpringApplication from Spring Boot, why not finish the job and use #EnableAutoConfiguration as well, and also the Maven plugin (see for example this guide)? That way you will get something working pretty quickly and you can always add your own features later.
If the first argument to the CommandLineJobRunner is your #Configuration FQCN instead of a resource path, the ClassPathXmlApplicationContext constructor that's called from the CommandLineJobRunner's start() method will break.
int start(String jobPath, String jobIdentifier, String[] parameters, Set<String> opts) {
ConfigurableApplicationContext context = null;
try {
context = new ClassPathXmlApplicationContext(jobPath);
If you've already written a class with a main(), that replaces the CLJR, you shouldn't be passing CLJR as the class name in the command line. Pass that instead.
dont use spring.batch.job.enabled=false
then run using java -jar [jar-files] --spring.batch.job.names=[job-name]

Resources