How to pass maven variable to springboot application - spring-boot

I want to pass variable from maven command line to spring boot main class,but i have no idea,here is my maven pom file:
<properties>
<maven.tomcat.home>Here should add argument from command line</maven.tomcat.home>
</properties>
Here is my spring boot main class:
#PropertySource(value ={"file:#maven.tomcat.home#/em/easymobile-application.properties"})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
So when i run maven by command line as below ,the application will deploy as war file to tomcat
mvn clean install -Dmaven.tomcat.home=/usr/local/apache-tomcat-8.0.33/webapps
Then i start up tomcat,the error says easymobile-application.properties is not found,so do you know how to load the easymobile-application.properties from maven command line using #PropertySource or something else.Thanks!!

I don't think that's the right approach, assuming at some point you get that to work, what happens if you need / have to deploy the webapp to /usr/local/apache-tomcat-8.0.xx? Would you need to compile the artifact again? That's not good. A better approach is to only produce 1 binary / artifact that could be deployed / installed in every environment: staging / prod / etc..
Like mentioned before, if the app needs files path configuration, I would suggest to use a config properties file instead of a Maven property.

Thanks! I have solved the problem using a simple way ,i just add the path of the folder which contains application.properties in tomcat\bin\catalina.sh
CLASSPATH=:/usr/local/apache-tomcat-8.0.33
the #PropertySource points to "classpath:em/easymobile-application.properties"

Related

Spring Boot Application - Running jar file gives ResourceFinderException error

Created a jar file for a spring boot multimodule application and ran the jar file using java -jar command. While starting the application, it gives ResourceFinderException. When I analyzed it, the issue is happening because in my ResourceConfig file, i have used the package for my api end points. If I use register(service.class), the application starts fine. Any suggestion how can I provide the package instead of using register? The reason I want to use package is because I have lots of services inside multiple packages and the code looks very ugly if i use register for all the services. The ResourceConfig file looks like below.
public class AppResourceConfig extends ResourceConfig {
public AppResourceConfig {}{
super();
property("jersery.config.beanValidation.enableOutputValidationErrorEntity.server");
**packages("com.api");**
register(GsonProvider.class);
register(RequestContextFilter.class);
register(NotFoundExceptionMapper.class);
register(DefaultExceptionMapper.class);
}
}
Here the issue is with highlighted line: packages("com.api")
If I comment out this code application will be up. Otherwise it is giving org.glassfish.jersey.server.internal.scanning.ResourceFinderException: java.io.FileNotFoundException: api-01.03.00.04-snapshot.jar (No such file or direcotry)
Note: api-01.03.00.04-snapshot.jar is the jar file for one of the module in a project

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

Spring boot on Tomcat with external configuration

I can't find an answer to this question on stackoverflow hence im asking here so I could get some ideas.
I have a Spring Boot application that I have deployed as a war package on Tomcat 8. I followed this guide Create a deployable war file which seems to work just fine.
However the issue I am currently having is being able to externalize the configuration so I can manage the configuration as puppet templates.
In the project what I have is,
src/main/resources
-- config/application.yml
-- config/application.dev.yml
-- config/application.prod.yml
-- logback-spring.yml
So how can I possibly load config/application.dev.yml and config/application.prod.yml externally and still keep config/application.yml ? (contains default properties including spring.application.name)
I have read that the configuration is load in this order,
A /config subdirectory of the current directory.
The current directory
A classpath /config package
The classpath root
Hence I tried to load the configuration files from /opt/apache-tomcat/lib to no avail.
What worked so far
Loading via export CATALINA_OPTS="-Dspring.config.location=/opt/apache-tomcat/lib/application.dev.yml"
however what I would like to know is,
Find out why loading via /opt/apache-tomcat/lib classpath doesn't work.
And is there a better method to achieve this ?
You are correct about load order. According to Spring boot documentation
SpringApplication will load properties from application.properties files in the following locations and add them to the Spring Environment:
A /config subdirectory of the current directory.
The current directory
A classpath /config package
The classpath root
The list is ordered by precedence (properties defined in locations higher in the list override those defined in lower locations).
[Note]
You can also use YAML ('.yml') files as an alternative to '.properties'.
This means that if you place your application.yml file to /opt/apache-tomcat/lib or /opt/apache-tomcat/lib/config it will get loaded.
Find out why loading via /opt/apache-tomcat/lib classpath doesn't work.
However, if you place application.dev.yml to that path, it will not be loaded because application.dev.yml is not filename Spring is looking for. If you want Spring to read that file as well, you need to give it as option
--spring.config.name=application.dev or -Dspring.config.name=application.dev.
But I do not suggest this method.
And is there a better method to achieve this ?
Yes. Use Spring profile-specific properties. You can rename your files from application.dev.yml to application-dev.yml, and give -Dspring.profiles.active=dev option. Spring will read both application-dev.yml and application.yml files, and profile specific configuration will overwrite default configuration.
I would suggest adding -Dspring.profiles.active=dev (or prod) to CATALINA_OPTS on each corresponding server/tomcat instance.
I have finally simplified solution for reading custom properties from external location i.e outside of the spring boot project. Please refer to below steps.
Note: This Solution created and executed windows.Few commands and folders naming convention may vary if you are deploying application on other operating system like Linux..etc.
1. Create a folder in suitable drive.
eg: D:/boot-ext-config
2. Create a .properties file in above created folder with relevant property key/values and name it as you wish.I created dev.properties for testing purpose.
eg :D:/boot-ext-config/dev.properties
sample values:
dev.hostname=www.example.com
3. Create a java class in your application as below
------------------------------------------------------
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
#PropertySource("classpath:dev.properties")
#ConfigurationProperties("dev")
public class ConfigProperties {
private String hostname;
//setters and getters
}
--------------------------------------------
4. Add #EnableConfigurationProperties(ConfigProperties.class) to SpringBootApplication as below
--------------------------------------------
#SpringBootApplication
#EnableConfigurationProperties(ConfigProperties.class)
public class RestClientApplication {
public static void main(String[] args) {
SpringApplication.run(RestClientApplication.class, args);
}
}
---------------------------------------------------------
5. In Controller classes we can inject the instance using #Autowired and fetch properties
#Autowired
private ConfigProperties configProperties;
and access properties using getter method
System.out.println("**********hostName******+configProperties.getHostName());
Build your spring boot maven project and run the below command to start application.
-> set SPRING_CONFIG_LOCATION=<path to your properties file>
->java -jar app-name.jar

Spring Boot - deploy .properties file to a folder different than 'WEB-INF/classes'

I'm trying to convert a traditional Tomcat Spring MVC webapp to Spring Boot. The new application should still use .war deployment.
For various reasons I have the obligatory requirement that the application.properties file resides inside a WEB-INF/conf folder in the deployed app and NOT inside the WEB-INF/classes folder where Spring Boot puts it by default.
In the original webapp I could put the application.properties file inside the src/main/webapp/WEB-INF/conf folder (so they get copied to WEB-INF/conf in the deployed application) and then use it like this:
<context:property-placeholder location="/WEB-INF/conf/application.properties"/>
What is the Spring Boot way to refer to this location?
I tried adding each of the following:
spring.config.location=WEB-INF/conf/application.properties
but my application.properties file still doesn't get loaded.
What finally worked was the following #PropertySource annotation.
#SpringBootApplication
#PropertySource(value = {"WEB-INF/conf/application.properties"})
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
It seems that not specifying classpath: or file: at the beginning of a path makes it use a path relative to the webapp.
I'm still not sure as to why specifying
spring.config.location=WEB-INF/conf/application.properties
didn't have the same effect.

Resources