Home > Software design >  'maven package' command not picking up externalized .properties file
'maven package' command not picking up externalized .properties file

Time:07-31

I'm building a backend servie using spring boot. The packaging type is war. I externalized the main application config, including RSA private keys in a file named env.properties located at the project root folder(right next to pom.xml). In the main application.properties file, I have all the same fields that reference the fields in the env.properties file. I put application.properties in version control, not the env.properties.

My purpose of doing so is that I can keep the real production config away from version control and make each delopyment flexible in terms of configuration.

During development, the setup works fine, but the problem comes when I try to deploy the application. After running mvn clean build, I get a .war file, which won't start (404) when I deploy it on tomcat9. If I try to run the .war file with java -jar xxx.war, the output is

$ java -jar xxx.war
23:04:12.260 [main] DEBUG org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter - Application failed to start due to an exception
org.springframework.boot.context.config.ConfigDataResourceNotFoundException: Config data resource 'file [env.properties]' via location 'file:env.properties' cannot be found
        at org.springframework.boot.context.config.ConfigDataResourceNotFoundException.withLocation(ConfigDataResourceNotFoundException.java:97)
        at org.springframework.boot.context.config.ConfigDataImporter.handle(ConfigDataImporter.java:145)
        at org.springframework.boot.context.config.ConfigDataImporter.load(ConfigDataImporter.java:136)
        at org.springframework.boot.context.config.ConfigDataImporter.resolveAndLoad(ConfigDataImporter.java:86)
        at org.springframework.boot.context.config.ConfigDataEnvironmentContributors.withProcessedImports(ConfigDataEnvironmentContributors.java:116)
        at org.springframework.boot.context.config.ConfigDataEnvironment.processInitial(ConfigDataEnvironment.java:240)
        at org.springframework.boot.context.config.ConfigDataEnvironment.processAndApply(ConfigDataEnvironment.java:227)
        at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:102)
        at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:94)
        at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEnvironmentPreparedEvent(EnvironmentPostProcessorApplicationListener.java:102)
        at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEvent(EnvironmentPostProcessorApplicationListener.java:87)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:176)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:169)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:143)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:131)
        at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:85)
        at org.springframework.boot.SpringApplicationRunListeners.lambda$environmentPrepared$2(SpringApplicationRunListeners.java:66)
        at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
        at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:120)
        at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:114)
        at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:65)
        at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:339)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:297)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1312)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1301)
        at com.jnairport.yqpay.YqpayApplication.main(YqpayApplication.java:10)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:108)
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
        at org.springframework.boot.loader.WarLauncher.main(WarLauncher.java:59)
23:04:12.267 [main] ERROR org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter - 

***************************
APPLICATION FAILED TO START
***************************

Description:

Config data resource 'file [env.properties]' via location 'file:env.properties' does not exist

Action:

Check that the value 'file:env.properties' at class path resource [application.properties] - 1:22 is correct, or prefix it with 'optional:'

It seems when I package the application for deployment, maven didn't pick up the env.properties file. The whole app won't run at all.

I've tried to search for solutions but got no clue. Please help, thanks.

CodePudding user response:

I sense two issues (writing sense as it's hard to be sure without a reproducible example):

  • referencing a file by file:env.properties is error-prone, as this path is different on every system
  • maven doesn't know about the env.properties file and there for it doesn't include it in the package

Let's tackle that one by one

Resource location

Your reference file:env.properties is ambiguous. When you define your resource location with file it uses FileSystemResource underneath. See spring documentation on FileSystemResource Caveats.

So when you write your test, your IDE looks for a project root path. But when you are running the jar file - the path might be different. That might be the reason why app is unable to find a properties file.

Probably the best approach would be to pack the env.properties into the war file during the build process or (even better) set the values in the properties file as environment variables

Packaging with Maven

You can include your env.properties in your application classpath, without versioning it. That way you can refer to the file with classpath:env.properties within your application codebase

You will need to extend your Maven build file with additional resource location

CodePudding user response:

Thanks for the reply from Jakub Marchwicki, it's quite detailed. I believe it's going to help a lot of people who may have searched for a similar issue in the future.

I solved the problem by ditching the whole idea of using the env.properties file for externalized config. After some study I found a better way of using spring profiles, where I keep config files for different profiles and reference the needed one in application.properties file.

For example, I could have a application-development.properties file and a application-production.properties file. When in development, the first config file is referenced in the main application.properties file whereas in production, the second one is referenced. The config file for production is not version controlled of course.

You may find this article useful: https://springframework.guru/spring-profiles/

Hope it helps, cheers!

  • Related