user1154644
user1154644

Reputation: 4607

Why does Spring's PropertySource throw a FileNotFoundException?

I am trying to load a properties file using Spring, that is located in my WEB-INF folder.

I am receiving the following error:

org.springframework.beans.factory.BeanDefinitionStoreException: Failed to parse configuration class [com.elastictest.config.ProdConfig]; nested exception is java.io.FileNotFoundException: \WEB-INF\config\prod.properties (The system cannot find the path specified)

Here is my Production Configuration file:

@Configuration
@Profile("prod")
@PropertySource("file:${prodPropertiesFile}")
public class ProdConfig {

    @Bean
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }

}

Here is my web.xml declaration:

<context-param>
    <param-name>prodPropertiesFile</param-name>
    <param-value>/WEB-INF/config/prod.properties</param-value>
</context-param>

I have opened the war and verified that the properties file is there under WEB-INF/config folder. Any ideas?

Upvotes: 1

Views: 2973

Answers (3)

Sotirios Delimanolis
Sotirios Delimanolis

Reputation: 280174

The locations you specify within the @PropertySource annotation are processed by a ResourceLoader. In this case, that will be your AnnotationConfigWebApplicationContext, since this is a web application and you want to use an annotation configuration.

As a ResourceLoader implementation, AnnotationConfigWebApplicationContext knows how to resolve location values to find and initialize Resource objects. It uses these to create ResourcePropertySource objects which are used in property resolution.

The location value resolution follows a few steps:

  • If it starts with a /, it's interpreted as a servlet context resource and Spring attempts to retrieve it through ServletContext#getResourceAsStream.

  • If it starts with classpath:, it's interpreted as a classpath resource and Spring tries to retrieve it through ClassLoader#getResourceAsStream, given an appropriate ClassLoader.

  • Otherwise, it defers resolution to a UrlResource which uses the URL to locate a resource. Its javadoc states

    Supports resolution as a URL and also as a File in case of the "file:" protocol.

In your case, you prefixed your location with file: so Spring tried to use the UrlResource. Your path had a leading / which the file system will consider as the beginning of an absolute path. You obviously don't have a file at that location, /WEB-INF/config/prod.properties.

If you use a classpath: prefix as suggested in this answer, then you must make sure that /WEB-INF/config/prod.properties is on the classpath. That's a very uncommon thing to put on the classpath, so I don't recommend it.

Finally, as you've found out, you could use

@PropertySource("/WEB-INF/config/prod.properties")
// or to support your property
@PropertySource("${prodPropertiesFile}")

which will attempt to retrieve a resource through the ServletContext. Its javadoc states

The path must begin with a / and is interpreted as relative to the current context root

Your WEB-INF folder will be in the context root (basically a directory chosen for your Servlet container as the root of your web application) and so the resource will be found and used.


You can read more about Resource in the official documentation, here, and about the ResourceLoader process, here.

Upvotes: 7

user1154644
user1154644

Reputation: 4607

It turned out to be simpler than I was making it:

@PropertySource("/WEB-INF/config/prod.properties")

Upvotes: -2

Sai Ye Yan Naing Aye
Sai Ye Yan Naing Aye

Reputation: 6738

No need web.xml declaration. Try like this

@PropertySource(name="prodPropertiesFile", value="classpath:/WEB-INF/config/prod.properties")
public class ProdConfig {
}

Upvotes: -1

Related Questions