application.properties value is not being evaluated correctly across platforms - spring

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.
"""

Related

Is it possible to send a application.properties file in arguments through a Jar file?

I have a Springboot project and I know I can send a application.properties file as a argument, but is this possible using a jar file?
I built my jar file using maven and in my application I have this piece of code that runs the programm if the user sent the argument run.
Is there any method that allows me to set the application properties if I receive it through argument? Or does the override of the file happens automatically as it does when I use the command
mvn spring-boot:run -Dspring.config.location=your.properties
if (args[0].equals("run")) {
ConfigurableApplicationContext ctx = SpringApplication.run(MigrationsApplication.class, args);
int exitCode = SpringApplication.exit(ctx, () -> 0);
System.exit(exitCode);
}
For jar you can either pass one of the properties or the complete or its location as beow.
we can configure the location directly in the command line:
java -jar app.jar --spring.config.location=file:///Users/home/config/jdbc.properties
We can also pass a folder location where the application will search for the file:
java -jar app.jar --spring.config.name=application,jdbc --spring.config.location=file:///Users/home/config
And, an alternative approach is running the Spring Boot application through the Maven plugin. There, we can use a -D parameter:
mvn spring-boot:run -Dspring.config.location="file:///Users/home/jdbc.properties"

How to pass spring.config.location="somepath" while building SpringBoot application with command-line Gradle (6.4) build

I have a SpringBoot application where I have application.properties file outside of project (it's not in usual place src/main/resources).
While building application with gradle clean build, it fails as code is not able to find properties files.
I have tried many command to pass vm args, gradle opts but its not working.
gradle clean build -Djvmargs="-Dspring.config.location=/users/home/dev/application.properties" //not working
It fails on test phase when it creates Spring application context and not able to substitute property placeholders. If I skip test as gradle clean build -x test it works.
Though I can run the app with java -jar api.jar --spring.config.location=file:/users/home/dev/application.properties
Please help how I can pass spring.config.location=/users/home/dev/application.properties in gradle build using command line so that build runs with all Junit tests
If I were you, I would not get involved the actual properties to junit test. So I would create a test properties for the project under src/test/resources/application-test.properties and in junit test I would load the test properties.
Example:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = MyProperties.class)
#TestPropertySource("classpath:application-test.properties")
public class MyTestExample{
#Test
public void myTest() throws Exception {
...
}
}
System properties for running Gradle are not automatically passed on to the testing framework. I presume this is to isolate the tests as much as possible so differences in the environment will not lead to differences in the outcome, unless explicitly configured that way.
If you look at the Gradle API for the Test task, you can see that you can configure system properties through through the systemProperty method on the task (Groovy DSL):
test {
systemProperty "spring.config.location", "/path/to/my/configuration/repository/application.properties"
}
If you also want to read a system property from the Gradle command line and then pass that the test, you have to read it from Gradle first, e.g. as a project property, and then pass that value to the test:
test {
if (project.hasProperty('testconfig')) {
systemProperty 'spring.config.location', project.getProperty('testconfig')
}
}
Run it with gradle -Ptestconfig="/path/to/my/configuration/repository/application.properties" build
However, I would discourage using system properties on the build command line if you can avoid it. At the very least, it will annoy you greatly in the long run. If the configuration file can be in different locations on different machines (depending on where you have checkout out the repository and if it is not in the same relative path to your Spring Boot repository), you may want to specify it in a personal gradle.properties file instead.
I think there is a misunderstanding.
spring.config.location is used at runtime
As you validated:
java -jar api.jar --spring.config.location=file:/users/home/dev/application.properties
spring.config.location is used or required at runtime, not at build time.
When your spring boot app is building, an application.properties is required. An approach could be use an src/main/resources/application.properties with template values, but at runtime you will ignore it spring.config.location=file...
For unit tests
In this case as #nikos-bob said, you must use another properties, commonly inside of your src/test/resources
Environment variables instead external properties
We don't want to have hardcoded values in our main git repository src/main/resources/application.properties so the first idea is use an external properties. But this file must be stored in another git repository (equal to main repository ) or manually created.
Spring and other frameworks give us an alternative: Use environment variables.
So instead of manually external creation of application.properties or store it in our git repository, your spring boot app always must have an application.properties but with environment variables:
spring.datasource.url=jdbc:oracle:thin:#${DATABASE_HOST}:${DATABASE_PORT}:${DATABASE_SID}
spring.datasource.username=${DATABASE_USER}
spring.datasource.password=${DATABASE_PASSWORD}
spring.mail.host = ${MAIL_HOST}
spring.mail.username =${MAIL_USERNAME}
spring.mail.password =${MAIL_PASSWORD}
Advantages:
No manually creation of application.properties allowing us a more easy devops automations
No spring.config.location=file.. is required

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 adding a custom command to actuatorshell in java

I am trying to add a java command to spring-actuator's ssh remote shell in a spring-boot applicaton. The spring-boot version is 1.2.3.RELEASE.
My sample command is just named 'kafka' and I tried placing it on the classpath in both /crash/commands as well as just /commands. It is never found - it doesn't show up in the help or actually work.
Is there some way to ask the remote shell to tell me what it's scanning/finding when it starts?
Things I have tried include specfically overriding shell.commandPathPatterns though the default seems like it should cover it.
My command - for testing - is very simple:
package commands;
#Usage("Kafka utility commands")
public class kafka extends BaseCommand {
#Command
public Object main(InvocationContext<ObjectName> context) {
return "it's all good";
}
}
After one hour of debugging I've found that the CRaSH remote shell looks for files with the extensions .groovy or .java within the packages are commands and crash.commands. The found files are compiled to bytecode, compiler errors are ignored.
I presume you use something like Maven. When you put your command into src/main/java then Maven will compile it as .class file and CRaSH will not find it. When you put your command into src/main/resources then Maven will not compile it and keep it as .java file instead.
The solution (which is quite odd for me) is to put your java command file into src/main/resources (package commands or crash.commands) so you have a .java source file in your target directory or JAR.
I tested it with spring-boot 1.2.1.RELEASE (crash.shell: 1.3.0) which should not be much different than 1.2.3.RELEASE (crash.shell: 1.3.1).

Extern log4.properties file with Spring Boot

I am running my app with executable jar.
I have log4j.properties inside /resources folder
In prod I would like to override it and have it within external dir
How I could do that using Spring-Boot?
-Dlogging.config=/path/to/log4j.properties
http://docs.spring.io/spring-boot/docs/current/reference/html/howto-logging.html
If you don't like to add command line arguments, you can make additional application.properties on the directory where you start the application. like:
# log4j configuration for product
logging.config=log4j-prod.properties
Then, this application.properties will override the /resources/application.properties and, the log4j-prod.properties will be used on the product environment. Please read more details on:
http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-application-property-files
try this:
java -Dlog4j.configuration=file:/log4j.properties -jar XX.jar
the -D configuration before the -jar configuration.
work for me.
-Dlog4j.configuration=file:/path/to/log4j.properties to the command line works in Spring Boot 1.5.6. Don't forget file: .

Resources