Specifying relative path in application.properties in Spring
Asked Answered
U

3

21

Is there a way we can lookup file resources using relative path in application.properties file in Spring boot application as specified below

spring.datasource.url=jdbc:hsqldb:file:${project.basedir}/db/init
Usance answered 29/4, 2016 at 14:6 Comment(0)
C
8

@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:

  1. This will not work outside the local workspace as it depends on the source code structure.

  2. I've assumed a Gradle project structure here /build/classes/main. If necessary, adjust according to your build tool.

  3. If MyApplicationContextInitializer is in the src/test/java, pwd will be <projectBasedir>/build/classes/test/, not <projectBasedir>/build/classes/main/.

Colcothar answered 26/2, 2017 at 22:9 Comment(0)
B
16

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
Bergerac answered 10/5, 2017 at 10:54 Comment(3)
Who said the upload folder would be under the home directory?Colcothar
@AbhijitSarkar do we have a standard to this?Bergerac
Any resource should be part of the projectColcothar
C
8

@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:

  1. This will not work outside the local workspace as it depends on the source code structure.

  2. I've assumed a Gradle project structure here /build/classes/main. If necessary, adjust according to your build tool.

  3. If MyApplicationContextInitializer is in the src/test/java, pwd will be <projectBasedir>/build/classes/test/, not <projectBasedir>/build/classes/main/.

Colcothar answered 26/2, 2017 at 22:9 Comment(0)
M
0
your.basedir=${project.basedir}/db/init
spring.datasource.url=jdbc:hsqldb:file:${your.basedir}

@Value("${your.basedir}")
private String file;

new ClassPathResource(file).getURI().toString()
Mohn answered 29/4, 2016 at 14:9 Comment(4)
does ${project.basedir} work within Spring containerUsance
Receive java.lang.IllegalArgumentException: Could not resolve placeholder 'basedir' in string value "jdbc:hsqldb:file:${basedir}/db/init"Usance
so you have a variable before declared named basedir=...? than it should work. of course it must be declared before reusing the placehodler.Mohn
This is just breaking up the hardcoded path in 2 parts. What the OP is looking for is a property that Boot can resolve, not what a user configures.Colcothar

© 2022 - 2024 — McMap. All rights reserved.