You cannot read a File from inside a JAR. This fails due to the fact that the File has to point to an actual file resource on the file system and not something inside a JAR.
Let Spring do the heavy lifting and use the Resource abstraction to hide the nasty internals. So instead of using a String use a Resource and prefix the value of the property with classpath: to make sure it is loaded from the classpath. Then use an InputStreamReader instead of FileReader to obtain the information you need.
@Value("${pont.email.template.location}")
private Resource templateLocation;
----------------
BufferedReader reader = new BufferedReader(new InputStreamReader(templateLocation.getInputStream()));
In your application.properties prefix with classpath:.
pont.email.template.location=classpath:templates/mailTemplate.html
Now it should work regardless of the environment you are running in.
Answer from M. Deinum on Stack OverflowIf you want to use difference application.properties in difference path, use this command to start the jar file
nohup java -jar project.jar --spring.config.location=file://{file-path}/application.properties
environment variable SPRING_CONFIG_LOCATION can be also used.
https://docs.spring.io/spring-boot/docs/current/reference/html/howto-properties-and-configuration.html
Videos
I'm using spring boot to build a upload sample, and meet the same problem, I only want to get the project root path. (e.g. /sring-boot-upload)
I find out that below code works:
upload.dir.location=${user.dir}\\uploadFolder
@membersound answer is just breaking up the hardcoded path in 2 parts, not dynamically resolving the property. I can tell you how to achieve what you're looking for, but you need to understand is that there is NO project.basedir when you're running the application as a jar or war. Outside the local workspace, the source code structure doesn't exist.
If you still want to do this for testing, that's feasible and what you need is to manipulate the PropertySources. Your simplest option is as follows:
Define an ApplicationContextInitializer, and set the property there. Something like the following:
public class MyApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext appCtx) {
try {
// should be /<path-to-projectBasedir>/build/classes/main/
File pwd = new File(getClass().getResource("/").toURI());
String projectDir = pwd.getParentFile().getParentFile().getParent();
String conf = new File(projectDir, "db/init").getAbsolutePath();
Map<String, Object> props = new HashMap<>();
props.put("spring.datasource.url", conf);
MapPropertySource mapPropertySource = new MapPropertySource("db-props", props);
appCtx.getEnvironment().getPropertySources().addFirst(mapPropertySource);
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}}
Looks like you're using Boot, so you can just declare context.initializer.classes=com.example.MyApplicationContextInitializer in your application.properties and Boot will run this class at startup.
Words of caution again:
This will not work outside the local workspace as it depends on the source code structure.
I've assumed a Gradle project structure here
/build/classes/main. If necessary, adjust according to your build tool.If
MyApplicationContextInitializeris in thesrc/test/java,pwdwill be<projectBasedir>/build/classes/test/, not<projectBasedir>/build/classes/main/.
Classpath includes what you have inside you resources dir.
Try:
cert.file=classpath:cert.p12
I'm assuming that you have standard maven catalog structure.
This syntax doesn't work with a normal FileInputStream. Use the Spring Resourceloader instead.
@Autowired
private ResourceLoader resourceLoader;
@Value("${property.name}")
private String property;
File getPropertyFile(){
return resourceLoader.getResource(property).getFile();
}
application.properties
property.name=classpath:filename.txt