How to read properties file in web application?
Several notes:
You should prefer the
ClassLoader
as returned byThread#getContextClassLoader()
.ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
This returns the parentmost classloader which has access to all resources. The
Class#getClassLoader()
will only return the (child) classloader of the class in question which may not per se have access to the desired resource. It will always work in environments with a single classloader, but not always in environments with a complex hierarchy of classloaders like webapps.The
/WEB-INF
folder is not in the root of the classpath. The/WEB-INF/classes
folder is. So you need to load the properties files relative to that.classLoader.getResourceAsStream("/auth.properties");
If you opt for using the
Thread#getContextClassLoader()
, remove the leading/
.
The JSF-specific ExternalContext#getResourceAsStream()
which uses ServletContext#getResourceAsStream()
"under the hoods" only returns resources from the webcontent (there where the /WEB-INF
folder is sitting), not from the classpath.
Where to place and how to read configuration resource files in servlet based application?
It's your choice. There are basically three ways in a Java web application archive (WAR):
1. Put it in classpath
So that you can load it by ClassLoader#getResourceAsStream()
with a classpath-relative path:
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
InputStream input = classLoader.getResourceAsStream("foo.properties");
// ...
Properties properties = new Properties();
properties.load(input);
Here foo.properties
is supposed to be placed in one of the roots which are covered by the default classpath of a webapp, e.g. webapp's /WEB-INF/lib
and /WEB-INF/classes
, server's /lib
, or JDK/JRE's /lib
. If the propertiesfile is webapp-specific, best is to place it in /WEB-INF/classes
. If you're developing a standard WAR project in an IDE, drop it in src
folder (the project's source folder). If you're using a Maven project, drop it in /main/resources
folder.
You can alternatively also put it somewhere outside the default classpath and add its path to the classpath of the appserver. In for example Tomcat you can configure it as shared.loader
property of Tomcat/conf/catalina.properties
.
If you have placed the foo.properties
it in a Java package structure like com.example
, then you need to load it as below
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
InputStream input = classLoader.getResourceAsStream("com/example/foo.properties");
// ...
Note that this path of a context class loader should not start with a /
. Only when you're using a "relative" class loader such as SomeClass.class.getClassLoader()
, then you indeed need to start it with a /
.
ClassLoader classLoader = getClass().getClassLoader();
InputStream input = classLoader.getResourceAsStream("/com/example/foo.properties");
// ...
However, the visibility of the properties file depends then on the class loader in question. It's only visible to the same class loader as the one which loaded the class. So, if the class is loaded by e.g. server common classloader instead of webapp classloader, and the properties file is inside webapp itself, then it's invisible. The context class loader is your safest bet so you can place the properties file "everywhere" in the classpath and/or you intend to be able to override a server-provided one from the webapp on.
2. Put it in webcontent
So that you can load it by ServletContext#getResourceAsStream()
with a webcontent-relative path:
InputStream input = getServletContext().getResourceAsStream("/WEB-INF/foo.properties");
// ...
Note that I have demonstrated to place the file in /WEB-INF
folder, otherwise it would have been public accessible by any webbrowser. Also note that the ServletContext
is in any HttpServlet
class just accessible by the inherited GenericServlet#getServletContext()
and in Filter
by FilterConfig#getServletContext()
. In case you're not in a servlet class, it's usually just injectable via @Inject
.
3. Put it in local disk file system
So that you can load it the usual java.io
way with an absolute local disk file system path:
InputStream input = new FileInputStream("/absolute/path/to/foo.properties");
// ...
Note the importance of using an absolute path. Relative local disk file system paths are an absolute no-go in a Java EE web application. See also the first "See also" link below.
Which to choose?
Just weigh the advantages/disadvantages in your own opinion of maintainability.
If the properties files are "static" and never needs to change during runtime, then you could keep them in the WAR.
If you prefer being able to edit properties files from outside the web application without the need to rebuild and redeploy the WAR every time, then put it in the classpath outside the project (if necessary add the directory to the classpath).
If you prefer being able to edit properties files programmatically from inside the web application using Properties#store()
method, put it outside the web application. As the Properties#store()
requires a Writer
, you can't go around using a disk file system path. That path can in turn be passed to the web application as a VM argument or system property. As a precaution, never use getRealPath()
. All changes in deploy folder will get lost on a redeploy for the simple reason that the changes are not reflected back in original WAR file.
See also:
- getResourceAsStream() vs FileInputStream
- Adding a directory to tomcat classpath
- Accessing properties file in a JSF application programmatically
Reading properties file from the root of Web Application
Got Answer
String path = servletContext.getRealPath("/MyProps/MyProperty.properties");
System.out.println("path: " + path);
Properties prop = new Properties();
try {
prop.load(new FileInputStream(path));
} catch (Exception e) {
e.printStackTrace();
}
String name= prop.getProperty("name");
properties file in Web project
Your approach based on Class#getResourceAsStream(name)
will only work if and only if your file is accessible from the ClassLoader
of your calling class and here what you have directly under WEB-INF
is not accessible, you should move conf/conf.properties
in WEB-INF/classes
instead and use /conf/conf.properties
as resource name to make it get the file from the root not from the package of your calling class.
properties file not found within web application
The system class loader only knows about the core Java libraries, for example, those in java.lang., java.util., etc.
You want to load the properties file using the same class loader which looks at that JAR file, which is probably the same class loader that loaded your class.
Try something like this:
public class PropertyFileTest {
public void loadProperties() {
InputStream inputStream = PropertyFileTest.class.getResourceAsStream("/demo.properties");
properties.load(inputStream);
// do something with properties to see if it worked or not.
}
}
Note that I used Class.getResourceAsStream, which will use that class's class loader for you, per:
http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html
Read common external property file in Java Webapp and java normal app
You can add a <context>
to tomcat/conf/server.xml (in this example, linux path):
<Context docBase="/home/yourusername/tomcat/assests" path="/assets" />
If you are using Windows:
<Context docBase="C:\path\to\myapp\assets" path="/assets" />
And then you can access it like any other resource within your webapp (e.g.: /assets/myappConfig.property).
If you are using JDBC for example, you could store the connection properties in a Singleton and request it from there, and that class could take care of change checks on that file.
Where to store properties from properties file in java webapp
Register ServletContextListener to load Init parameters and properties at server start-up.
Load properties at single time and make it visible to other classes statically or you can store it in application context as well to access it from anywhere such as JSP and Servlet.
Note: Make the properties file location configurable in web.xml
rather than hard-coding it in Java class. You can retrieve the properties file location as system environment variable as well.
Sample code:
public class AppServletContextListener implements ServletContextListener {
private static Properties properties;
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
String cfgfile = servletContextEvent.getServletContext().getInitParameter("config_file");
properties.load(new FileInputStream(cfgfile));
// store it in application scope as well
servletContextEvent.getServletContext().setAttribute("prop",properties);
}
public static Properties getProperties(){
return properties;
}
}
web.xml:
<listener>
<listener-class>com.x.y.z.AppServletContextListener</listener-class>
</listener>
<context-param>
<param-name>config_file</param-name>
<param-value>config_file_location</param-value>
</context-param>
Please have a look at my another post that is asked in the same context:
- Retrieve Init parameters outside servlet
EDIT
If you are changing the properties at run-time then don't use Servlet context according to the ServletContext javadoc:
In the case of a web application marked "distributed" in its deployment descriptor, there will be one context instance for each virtual machine. In this situation, the context cannot be used as a location to share global information (because the information won't be truly global). Use an external resource like a database instead.
The Servlet specification also states in "SRV.4.4.1 Context Attributes in a Distributed Container":
Context attributes are local to the JVM in which they were created. This prevents ServletContext attributes from being a shared memory store in a distributed container. When information needs to be shared between servlets running in a distributed environment, the information should be placed into a session (See Chapter SRV.7, “Sessions”), stored in a database, or set in an Enterprise JavaBeansTM component.
In that case you can try with some third party cache that works in distributed environment as well as mentioned below:
- EHCache
- Infinispan
OR store all the properties in the database.
Load properties file within a web app
I experienced similar issues with different behaviours on different platforms when I use java.util.Properties
. In the end I settled with using Apache Commons - Java Configuration API:-
PropertiesConfiguration properties = new PropertiesConfiguration("my.properties");
String propertyValue = properties.getString("prop.key");
The path to my properties files are set in my JVM classpath prefix when I start my container.
Related Topics
Should Getters and Setters Be Synchronized
Getting Database Connection in Pure JPA Setup
Java - Swing Listen an Action in a Text Field of a Form
Converting Decimal to Binary Java
Parallel Streams, Collectors and Thread Safety
Using Javamail to Connect to Gmail Smtp Server Ignores Specified Port and Tries to Use 25
Find Place for Dedicated Application Folder
Must Spring Component Classes Be Thread-Safe
Is There a Newline Constant Defined in Java Like Environment.Newline in C#
JPA Query Selecting Only Specific Columns Without Using Criteria Query
Can't Cast to to Unspecific Nested Type with Generics
Class Not Found with Ant, Ivy and Junit - Error in Build.Xml
How to Automate Drag & Drop Functionality Using Selenium Webdriver Java
How to Check If a String Contains Only Ascii
Java.Lang.Noclassdeffounderror: Org/Hamcrest/Selfdescribing
How to Compile a .Java with Support for Older Versions of Java