Java Properties class throwing NPE when loading XML file within servlet? - java

All,
I have decided to adopt the java.util.Properties class within my servlets to facilitate easier maintenance of configs.
I am using the poperties class function loadFromXML to fetch an XML file that contains denatured (XML compliant ) SQL queries that my servlet will then execute.
Using this code which works fine in normal CLI Java application:
// retrieve all queries from xml from classpath
queries = new Properties();
try
{
String path = getServletContext().getRealPath("/WEB-INF");
System.out.println(path + "/queries.xml");
queries.loadFromXML(MyServlet.class.getResourceAsStream(path + "/queries.xml"));
}
catch (IOException io)
{
io.printStackTrace();
}
The output is a NULL Pointer Exception thrown by the loadFromXML method
java.lang.NullPointerException
at java.util.Properties.loadFromXML(Properties.java:851)
The file exists as produced by the system out message in the web server logs.
CORE3282: stdout: /u02/SunONE61060/testserver/myservlet/WEB-INF/queries.xml
I tried moving the XML file to the base directory where the Servlet class exists and call it from there but still the same NPE.
Any ideas?

Your problem is here:
MyServlet.class.getResourceAsStream(path + "/queries.xml")
This will return null. .getResourceAsStream() can only load from the classpath (for instance, /com/foo/myclass/MyResource.xml).
Since you have the absolute path of your resource, just use a standard FileInputStream, for instance.
Also: close your stream after you are done with it. Right now you don't: you have a resource leak. See the javadoc for Closeable.

You are attempting to load the resources from your classpath but are providing a real path. These two are not the same.
When you are using
MyServlet.class.getResourceAsStream("queries.xml")
Then the classloader will attempt to load the class from whereever your MyServlet.class file is, so if the package is my.pkg, it will attempt to load it from WEB-INF/classes/my/pkg/queries.xml.
You can also put the queries into the root of your class hierarchy (WEB-INF/classes/queries.xml) and load it like so:
MyServlet.class.getResourceAsStream("/queries.xml")
Then it will expect the file in WEB-INF/classes/queries.xml.
Alternatively, if you want to leave the file where it is, just use the servlet context to get the input stream:
getServletContext().getResourceAsStream("/WEB-INF/queries.xml")

It isn't valid to get a real path and then treat that as part of a resource path. It isn't. Make up your mind. Just do
getResourceAsStream("/WEB-INF/classes/.../queries.xml")
where the ... is the package of MyServlet, and put the resource file there.

Related

Why does getResourceAsStream() return null when File does not exist before start of Test method?

Before flagging this as a duplicate please read the question!
I have a JUnit Test which tests a method that writes its result in a file. To check the result I want to read that result file and check its content.
The problem is that when the result file does not already exist before the start of the test, the method getResourceAsStream() returns null.
My code for the Test is something like this:
#Inject
private ObjectToTest obj
#Test
public void testMethod() throws Exception {
// Do some setup (inject mocks, set properties of obj, ...)
obj.method(); // <-- Creates result.txt
Mockito.verify(obj).method();
// Thread.sleep(1000); <-- I have tried to use this to wait some time for the result, but it did not work
// This part is null on the first run of the test
// When I run the test the second time, the file does already exist and it returns the right InputStream for the File
InputStream resultInp = this.getClass().getResourceAsStream("/test-out/result.txt");
String resultStr = IOUtils.toString(resultInp, "UTF-8");
assertThat(resultStr).isNotNull();
assertThat(resultStr.split("\n")).hasSize(5);
}
Is there any explanation to why this happens or must it have to do something with another part of the code?
I have not found anything regarding this issue on StackOverflow, but if I am wrong please guide me to the right post.
The getResourceAsStream() method returns a stream for a resource on the classpath, using directory / index information that is cached by the classloader. If you add a resource to some directory tree or archive on the classpath after the classpath has been cached, the classloader is likely to not "see" it1.
That is most likely is what has happened in your test code.
A Java application should not be trying to treat classloader resources like a general purpose file system. Instead, use File or Path to denote files, and FileInputStream or similar to open them.
1 - The actual behavior does not appear to be specified in the javadocs for ClassLoader, etcetera. My description is based on the observed / reported behavior of some Java implementations.

NPE When Getting File. Works on IDE Run but Not Jar Launch [duplicate]

I have a simple java application that loads a properties file from the current package.
this.getClass().getResourceAsStream("props.properties");
This works fine when the property file I want is in the current package. However, I want to package this application as a JAR and define and override with a new properties file where I use it. Is there a way to load the first resource named "props.properties" that is on the classpath?
I want it to be as easy to override the properties file via command line:
java.exe -classpath props.properties;myJar.jar com.test.MyApp
I don't want to have to unpack the JAR and modify the properties file to change something. I feel like I'm missing something obvious...
The javadoc for Class.getResourceAsStream() documents the lookup logic:
If the name begins with a '/' ('\u002f'), then the absolute name of the resource is the portion of the name following the '/'.
Otherwise, the absolute name is of the following form:
modified_package_name/name
Where the modified_package_name is the package name of this object with '/' substituted for '.' ('\u002e').
So in other words, the resource name passed to the method should look like /com/package/p2/props.properties if the props.properties is stored in the com.package.p2 package instead of the current class's.
I'm sure it's too late for the answer but it could be interesting for googlers
this small code snippet helpers to load a properties file from any where in the Classpath.
ClassLoader cl = ClassLoader.getSystemClassLoader();
if (cl != null) {
URL url = cl.getResource(CONF_PROPERTIES);
if (url == null) {
url = cl.getResource("/" + CONF_PROPERTIES);
}
if (url != null) {
try {
InputStream in = url.openStream();
props = new Properties();
props.load(in);
} catch (IOException e) {
// Log the exception
} finally {
// close opened resources
}
}
}
If all else fails you could use two different file names, say props-default.properties inside myJar.jar and props.properties to override on the command-line. In your code, you'd try loading the props.properties file first and fallback to props-default.properties if it wasn't found.
I'm not sure, but maybe: ClassLoader.getResourceAsStream()
EDIT:
I don't think this is significantly different to this.getClass().getResourceAsStream() from the question, since as mentioned you still have to get the ClassLoader you want to use to load the resource.
Since you provide the resource in the -classpath in your example, it should be available from the same class loader as your "main" class (in the SUN JVM, that's sun.misc.Launcher$AppClassLoader, not sure if this can/does vary for other JVM implementations).

How to get a Resource in Apache Brooklyn

I am trying to build my own entity, which is based on VanillaWindowsProcess. The idea is, after the installation of the windows Machine, to execute some powershell commands, which are in a file.
I tried something which I used a lot of times in another Java projects to get a resource:
private void runInstallationScript() {
List<String> lines;
try {
lines = FileUtils.readLines(
new File(TalendWindowsProcessWinRmDriver.class.getResource("/my/path/file.txt").getFile()),
"utf-8");
executePsScript(lines);
} catch (IOException e) {
LOG.error("Error reading the file: ", e);
}
}
But I'm always getting the following:
ava.io.FileNotFoundException: File 'file:/opt/workspace/incubator-brooklyn/usage/dist/target/brooklyn-dist/brooklyn/lib/dropins/myProject-0.0.1-SNAPSHOT.jar!/my/path/file.txt' does not exist
It is strange, because the file is in the jar in that path. I did a test (without Apache Brooklyn infrastructure) and it works, but the other way, it does not.
The project follows the Maven standard structure and the file itself is under, src/main/resources/my/path/file.txt
Is there something that is wrong? Or maybe there is another approach to get that file? Any help would be appreciated.
You cannot access a resource inside a jar as a File object. You need to use an InputStream (or an URL) to access it.
Since you are already using getResource, you should change the method FileUtils.readLines to accept an InputStream (or an URL) as input.
If you don't have access to the source code, you can write your own method or use Files.readAllLines for Java >= 7.

properties file not found within web application

I am trying to invoke a Method present within a JAR file from my Web Application (A simple Servlet Application). Below is the code that method is using for accessing the properties file:
InputStream inputStream =
ClassLoader.getSystemClassLoader()
.getResourceAsStream("demo.properties");
properties.load(inputStream);
When this method is invoked using my Web Application, I am getting this NullPointerException:
java.lang.NullPointerException
at java.util.Properties$LineReader.readLine(Unknown Source)
at java.util.Properties.load0(Unknown Source)
at java.util.Properties.load(Unknown Source)
Possible reason for this exception is: My Web Application is not able to find the demo.properties file, hence the inputStream is NULL and this exception is thrown.
Please let me know:
How to resolve this exception.
Do I need to place the properties file manually within my Web Based Application? If yes then where exactly where to place this demo.properties file in my Web Application for resolving this exception.
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
The class loaders interprete the passed string as absolute path, hence as if it were /demo.properties (but never use the heading slash for ClassLoader.getResource). So open the war and look for /WEB-INF/classes/demo.properties. This must be case sensitive.
You might (in general) be interested in alternatives:
MyServletClass.class.getResourceAsStream("/demo.properties") -- better;
ResourceBundle bundle = ResourceBundle.get("demo");
Using Servlet's init parameters in /WEB-INF/web.xml.
ClassLoader does not identified which properties file location.
Use this code:
String path = AbcServiceImpl.class.getClassLoader().getResource("abc.properties").getFile().toString();
path = path.replace("%20", " ");
File f = new File(path);

File not found exception with external files

Hi i have made a small program that reads a config file. This file is stored outside the actual jar file. On the same level as the jarfile actually.
When i start my program from a commandline in the actual directory (ie. D:\test\java -jar name.jar argument0 argument1) in runs perfectly.
But when i try to run the program from another location then the actual directory i get the filenotfound exception (ie. D:\java -jar D:\test\name.jar argument0 argument1).
The basic functionality does seem to work, what am i doing wrong?
As requested a part of the code:
public LoadConfig() {
Properties properties = new Properties();
try {
// load the properties file
properties.load(new FileInputStream("ibantools.config.properties"));
} catch (IOException ex) {
ex.printStackTrace();
} // end catch
// get the actual values, if the file can't be read it will use the default values.
this.environment = properties.getProperty("application.environment","tst");
this.cbc = properties.getProperty("check.bankcode","true");
this.bankcodefile = properties.getProperty("check.bankcodefile","bankcodes.txt");
} // end loadconfig
The folder looks like this:
This works:
This doesn't:
The jar doesn't contain the text file.
When reading a File using the String/path constructors of File, FileInpustream, etc.. a relative path is derived from the working directory - the directory where you started your program.
When reading a file from a Jar, the file being external to the jar, you have at least two options :
Provide an absolute path: D:/blah/foo/bar
Make the directory where your file is located part of the class path and use this.getClass().getClassLoader().getResourceAsStream("myfile")
The latter is probably more appropriate for reading configuration files stored in a path relative to the location of your application.
There could be one more possibility:
If one part of your code is writing the file and another one is reading, then it is good to consider that the reader is reading before the writer finishes writing the file.
You can cross check this case by putting your code on debug mode. If it works fine there and gives you FileNotFoundException, then surely this could be the potential reason of this exception.
Now, how to resolve:
You can use retry mechanism something similar to below code block
if(!file..exists()){
Thread.sleep(200);
}
in your code and change the sleep value according to your needs.
Hope that helps.!!

Categories