How to Read Properties File in Web Application

How to read properties file in web application?

Several notes:

  1. You should prefer the ClassLoader as returned by Thread#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.

  2. 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



Leave a reply



Submit