Cannot read properties file in Java web app? - java

I am trying to read a properties file in my java web application. I have tried these solution:
Where to place and how to read configuration resource files in servlet based application?
Howto access properties file from Java EE web application?
But none of them worked for me.
Here is the structure of my app:
The code that reads the properties file is placed in the A class and it did not work even I put the absolute path. A is a normal Java class.
But everything worked like a charm if the reading properties code is place in the servlet class (ProcessRequest.java)
Here is the code I have used:
public class A {
public A() {
try {
Properties p = new Properties();
p.load(this.getClass().getClassLoader().getResourceAsStream("/a.properties"));
String n = p.getProperty("name");
System.out.println("name: " + n);
} catch (Exception ex) {
Logger.getLogger(A.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
Any idea?

You've put it in the servlets package, however you're trying it to get from the classpath root. The leading / makes the path relative to the classpath root.
Fix the path accordingly:
p.load(this.getClass().getClassLoader().getResourceAsStream("/servlets/a.properties"));
or, assuming that the current class is in servlets package already:
p.load(this.getClass().getClassLoader().getResourceAsStream("a.properties"));
Unrelated to the concrete problem, might it later happen that you move the properties file outside the WAR to an external location which allows easy editing of the file without the need to rebuild/redeploy everytime, then I'd suggest to use the thread's context class loader instead of the current class' class loader. It'll work in all circumstances:
p.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("servlets/a.properties"));
(note that the path doesn't need to start with / here, because it's always relative to classpath root)

Do you see the properties file under WEB-INF/servlets after building the application. If yes then try using following line.
p.load(getServletContext().getResourceAsStream("/WEB-INF/servlets/a.properties"));
instead of this
p.load(this.getClass().getClassLoader().getResourceAsStream("/a.properties"));

Related

java.lang.NullPointerException when using getClass().getResource() to load an image [duplicate]

I am trying to load an image to use as an icon in my application. The appropriate method according to this tutorial is:
protected ImageIcon createImageIcon(String path, String description)
{
java.net.URL imgURL = getClass().getResource(path);
if (imgURL != null) {
return new ImageIcon(imgURL, description);
} else {
System.err.println("Couldn't find file: " + path);
return null;
}
}
So, I placed the location of the file, and passed it as a parameter to this function. This didn't work, i.e. imgURL was null. When I tried creating the ImageIcon by passing in the path explicitly:
ImageIcon icon = new ImageIcon(path,"My Icon Image");
It worked great! So the application can pick up the image from an explicitly defined path, but didn't pick up the image using getResources(). In both cases, the value of the path variable is the same. Why wouldn't it work? How are resources found by the class loader?
Thanks.
getClass().getResource(path) loads resources from the classpath, not from a filesystem path.
You can request a path in this format:
/package/path/to/the/resource.ext
Even the bytes for creating the classes in memory are found this way:
my.Class -> /my/Class.class
and getResource will give you a URL which can be used to retrieve an InputStream.
But... I'd recommend using directly getClass().getResourceAsStream(...) with the same argument, because it returns directly the InputStream and don't have to worry about creating a (probably complex) URL object that has to know how to create the InputStream.
In short: try using getResourceAsStream and some constructor of ImageIcon that uses an InputStream as an argument.
Classloaders
Be careful if your app has many classloaders. If you have a simple standalone application (no servers or complex things) you shouldn't worry. I don't think it's the case provided ImageIcon was capable of finding it.
Edit: classpath
getResource is—as mattb says—for loading resources from the classpath (from your .jar or classpath directory). If you are bundling an app it's nice to have altogether, so you could include the icon file inside the jar of your app and obtain it this way.
As a noobie I was confused by this until I realized that the so called "path" is the path relative to the MyClass.class file in the file system and not the MyClass.java file. My IDE copies the resources (like xx.jpg, xx.xml) to a directory local to the MyClass.class. For example, inside a pkg directory called "target/classes/pkg. The class-file location may be different for different IDE's and depending on how the build is structured for your application. You should first explore the file system and find the location of the MyClass.class file and the copied location of the associated resource you are seeking to extract. Then determine the path relative to the MyClass.class file and write that as a string value with "dots" and "slashes".
For example, here is how I make an app1.fxml file available to my javafx application where the relevant "MyClass.class" is implicitly "Main.class". The Main.java file is where this line of resource-calling code is contained. In my specific case the resources are copied to a location at the same level as the enclosing package folder. That is: /target/classes/pkg/Main.class and /target/classes/app1.fxml. So paraphrasing...the relative reference "../app1.fxml" is "start from Main.class, go up one directory level, now you can see the resource".
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("../app1.fxml"));
Note that in this relative-path string "../app1.fxml", the first two dots reference the directory enclosing Main.class and the single "." indicates a file extension to follow. After these details become second nature, you will forget why it was confusing.
getResource by example:
package szb.testGetResource;
public class TestGetResource {
private void testIt() {
System.out.println("test1: "+TestGetResource.class.getResource("test.css"));
System.out.println("test2: "+getClass().getResource("test.css"));
}
public static void main(String[] args) {
new TestGetResource().testIt();
}
}
output:
test1: file:/home/szb/projects/test/bin/szb/testGetResource/test.css
test2: file:/home/szb/projects/test/bin/szb/testGetResource/test.css
getResourceAsStream() look inside of your resource folder. So the fil shold be placed inside of the defined resource-folder
i.e if the file reside in /src/main/resources/properties --> then the path should be /properties/yourFilename.
getClass.getResourceAsStream(/properties/yourFilename)

Property file not reflecting the modified changes using Apache Commons Configuration

I am trying to explore Apache commons configuration to dynamically load the property file and do modification in the file and save it.
I wrote a demo code for the same.
Code Snippet
package ABC;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy;
public class Prop {
public static void main(String[] args)
{
try {
URL propertiesURL = Prop.class.getResource("/d1.properties");
if (propertiesURL == null) {
System.out.println("null");
}
String absolutePath=propertiesURL.getPath();
PropertiesConfiguration pc = new PropertiesConfiguration(absolutePath);
pc.setReloadingStrategy(new FileChangedReloadingStrategy());
String s=(String)pc.getProperty("key_account_sales");
System.out.println("s is " + s);
pc.setAutoSave(true);
pc.setProperty("key_account_sales", "Dummy");
pc.save();
System.out.println("Modified as well");
String sa=(String)pc.getProperty("key_account_sales");
System.out.println("s is " + sa);
}catch(ConfigurationException ce)
{
ce.printStackTrace();
}
}
}
Although when I run the code multiple times, the updated value for the property is being properly shown but the changes are not seen in the Property file.
I tried refreshing the entire workspace and the project but still the property file shows the previous entry whereas this code displays the updated entry in console.
Why my property file is not getting updated?
Well I noticed that a new file with same name was formed inside bin
directory of my IDE workspace. This new file contains the required
changes.
However I still want that the old file should be updated with the new
value and instead of creating a new file, it should update in the old
file itself.
My property file is located inside a Web Application package say
Dem1
by the name of
Prop1.prop
I want to read this property file from in another class say
Reading.java
located inside another package
Dem2
, do changes in this same property file and show it to another user. It is a web application being deployed on an application server.
Even after using the absolute path in a simple file (main function) it is not reflecting the changes in the same file but updating it in new file.
I am doing a very slight mistake but can someone please help.
Using absolute path I am not able to make changes in the same property file in normal main method also. Please suggest.
New file in bin directory is created instead of updating the same file
in src folder.
You should be able to solve this using absolute paths. The PropertiesConfiguration class is finding your properties file somewhere on the classpath and only knows to write back to "d1.properties"; hence you have a file appearing in your bin directory.
The absolute path can be obtained by querying resources on the classpath. Something like the following:
URL propertiesURL = Prop.class.getResource("/d1.properties");
if (propertiesURL == null) {
// uh-oh...
}
String absolutePath = propertiesURL.getPath();
// Now use absolutePath

How to replace default properties in library

I am making the library that has the default properties in the file default.properties.
private static String defPropertyPath = "/database.properties";
I want to ask if this file can be replaced by the program that use my library. So the program will define the properties with the same name default.properties that will replace the properties from library. I created the default.properties in the program where i use the library, but the library is still loading the properties from their package.
edit:
I read the properties file via input stream:
InputStream ins = DbProperties.class.getResourceAsStream(defPropertyPath);
if (ins == null) {
logger.error("Can't find properties:" + pathToProperties);
return;
}
Edit: File structure:
DbLibrary.jar
/
/database.properties
/src
MyApplication.jar
/
/database.properties
/src
/lib/DbLibrary.jar
My application use the DbLibrary.jar and wants to force this library to use database.properties from MyApplication and not from the DbLibrary.
May be much clearer if your library exports some API that allows the user of your library to invoke an init method at any time.
public static void init(Properties p) { ... }
I'm not sure there is enough information to answer your question, but I'm going to guess that perhaps you included the "database.properties" file in the jar with your application. If you did that, the application will always read the file from the jar, and not from the file system.
You only have to override the properties file in these projects which include your library.

JarInputStream: getNextJarEntry always returns null

I have an I18n helper class that can find out the available Locales by looking at the name of the files inside the application's Jar.
private static void addLocalesFromJar(List<Locale> locales) throws IOException {
ProtectionDomain domain = I18n.class.getProtectionDomain();
CodeSource src = domain.getCodeSource();
URL url = src.getLocation();
JarInputStream jar = new JarInputStream(url.openStream());
while (true) {
JarEntry entry = jar.getNextJarEntry();
if (entry == null) {
break;
}
String name = entry.getName();
// ...
}
}
Currently, this isn't working - jar.getNextJarEntry() seems to always return null. I have no idea why that's happening, all I know is that url is set to rsrc:./. I have never seen that protocol, and couldn't find anything about it.
Curiously, this works:
class Main {
public static void main(String[] args) {
URL url = Main.class.getProtectionDomain().getCodeSource().getLocation();
JarInputStream jar = new JarInputStream(url.openStream());
while (true) {
JarEntry entry = jar.getNextJarEntry();
if (entry == null) {
break;
}
System.out.println(entry.getName());
}
}
}
In this version, even though there is practically no difference between them, the url is correctly set to the path of the Jar file.
Why doesn't the first version work, and what is breaking it?
UPDATE:
The working example really only works if I don't use Eclipse to export it. It worked just fine in NetBeans, but in the Eclipse version the URL got set to rsrc:./ too.
Since I exported it with Package required libraries into generated JAR library handling, Eclipse put its jarinjarloader in my Jar so I can have all dependencies inside it. It works fine with the other settings, but is there any way to make this work independently of them?
Another question
At the moment, that class is part of my application, but I plan to put it in a separate library. In that case, how can I make sure it will work with separate Jars?
The problem is the jarinjarloader ClassLoader that is being used by Eclipse. Apparently it is using its own custom rsrc: URL scheme to point to jar files stored inside the main jar file. This scheme is not understood by your URL stream handler factory, so the openStream() method returns null which causes the problem that you're seeing.
This answers the second part of your question about separate jars - not only will this work, it's the only way that it will work. You need to change your main application to use separate jars instead of bundling them all up inside the main jar. If you're building a web application, copy them into the WEB-INF/lib directory and you're fine. If you're building a desktop application, add a relative path reference in the META-INF/MANIFEST.MF to the other jars, and they will automatically be included as part of the classpath when you run the main jar.
The code may or may not result into the jar file where I18n resides. Also getProtectionDomain can be null. It depends how the classloader is implemented.
ProtectionDomain domain = I18n.class.getProtectionDomain();
CodeSource src = domain.getCodeSource();
URL url = src.getLocation();
about the rsrc:./ protocol, the classloader is free to use whatever URL they please (or name it for that matter)
try this out, you might get lucky :)
URL url = getClass().getResource(getClass().getSimpleName()+".class");
java.net.JarURLConnection conn = (java.net.JarURLConnection) url.openConnection();
Enumeration<JarEntry> e = conn.getJarFile().entries();
...
and good luck!
Eclipse's jarinjarloader loads everything using the system classloader and it never knows what jar file it was loaded from. That's why you can't get the jar URL for a rsrc: url.
I suggest storing the list of locales in a file in each application jar, e.g. META-INF/locales. Then you can use ClassLoader.getResources("META-INF/locales") to get the list of all the files with that name in the classpath and combine them to obtain the full list of locales.
I use System.getProperty("java.class.path") for getting the location of the jar. I do not know if that makes a difference. I have not explored the ProtectDomain path so I cannot help you there, sorry. As for multiple jars, just iterate through those jar file also.

How can I access a config file from a servlet deployed as a .war-file and running in Tomcat 5.5?

I'm trying to access a config file from a a servlet inside of .war-file. The problem is, that the default file path is the tomcat root itself and hardcoding the path to the file seems not like an option either. Is it possible to get any information through the ServletContext or any Tomcat variables?
If you put the file in the 'classes' directory under your specific webapps directory (./webapps/{servlet}/classes) then you can access it from inside a Java class by doing this :
Class.getResourceAsStream(<filename>);
so if you had a conf file at /webapps/myServlet/classes/conf.xml
Class.getResourceAsStream("conf.xml");
Gandalf has provided the "correct" answer. You can safely use this anywhere. It's all you need.
Just a caution. Some people assume that because there are ways to READ data from inside a WAR, that that means it's also OK to WRITE data inside a WAR. In the literal sense, sometimes that's true. But not always. And it's almost NEVER safe.
I mention this because I inherited an webapp that did exactly that. Stored a whole directory tree of files inside an exploded WAR directory. First software upgrade that came along, "Poof!" all those carefully uploaded data files were gone.
So treat WARs as read-only. If you need to write, designate a directory OUTSIDE the appserver. Preferably as a configurable parameter in your web.xml file so you can use JNDI to look it up and you can override it for testing purposes without having to modify source code.
I'm not at all sure that it's the "right" thing to do, but in the past, I've read an environment variable for the path to my configuration file.
Something like this (you should do a better job of handling the exceptions than this example does...but you get the point):
public File getConfigurationFile() {
String envPath = System.getEnv("CONFIG_FILE"); // Use a better-named variable
if(envPath == null || envPath.equals("") {
throw new RuntimeException("CONFIG_FILE environment variable not set.");
} else {
File f = new File(envPath);
if(!f.exists()) {
throw new RuntimeException("CONFIG_FILE environment variable points to non-existent file");
} else if(!f.isFile()) {
throw new RuntimeException("CONFIG_FILE environment variable points to non-file entity.");
} else if(!if.canRead()) {
throw new RuntimeException("CONFIG_FILE points to unreadable file.");
} else {
return f;
}
}
}

Categories

Resources