getResourceAsStream() is always returning null [duplicate] - java

This question already has answers here:
Where to place and how to read configuration resource files in servlet based application?
(6 answers)
Closed 6 years ago.
I have the following structure in a Java Web Application:
TheProject
-- [Web Pages]
-- -- [WEB-INF]
-- -- -- abc.txt
-- -- index.jsp
-- [Source Packages]
-- -- [wservices]
-- -- -- WS.java
In WS.java, I am using the following code in a Web Method:
InputStream fstream = this.getClass().getResourceAsStream("abc.txt");
But it is always returning a null. I need to read from that file, and I read that if you put the files in WEB-INF, you can access them with getResourceAsStream, yet the method is always returning a null.
Any ideas of what I may be doing wrong?
Btw, the strange thing is that this was working, but after I performed a Clean and Build on the Project, it suddenly stopped working :/

To my knowledge the file has to be right in the folder where the 'this' class resides, i.e. not in WEB-INF/classes but nested even deeper (unless you write in a default package):
net/domain/pkg1/MyClass.java
net/domain/pkg1/abc.txt
Putting the file in to your java sources should work, compiler copies that file together with class files.

A call to Class#getResourceAsStream(String) delegates to the class loader and the resource is searched in the class path. In other words, you current code won't work and you should put abc.txt in WEB-INF/classes, or in WEB-INF/lib if packaged in a jar file.
Or use ServletContext.getResourceAsStream(String) which allows servlet containers to make a resource available to a servlet from any location, without using a class loader. So use this from a Servlet:
this.getServletContext().getResourceAsStream("/WEB-INF/abc.txt") ;
But is there a way I can call getServletContext from my Web Service?
If you are using JAX-WS, then you can get a WebServiceContext injected:
#Resource
private WebServiceContext wsContext;
And then get the ServletContext from it:
ServletContext sContext= wsContext.getMessageContext()
.get(MessageContext.SERVLET_CONTEXT));

Instead of
InputStream fstream = this.getClass().getResourceAsStream("abc.txt");
use
InputStream fstream = this.getClass().getClassLoader().getResourceAsStream("abc.txt");
In this way it will look from the root, not from the path of the current invoking class

I think this way you can get the file from "anywhere" (including server locations) and you do not need to care about where to put it.
It's usually a bad practice having to care about such things.
Thread.currentThread().getContextClassLoader().getResourceAsStream("abc.properties");

I don't know if this applies to JAX-WS, but for JAX-RS I was able to access a file by injecting a ServletContext and then calling getResourceAsStream() on it:
#Context ServletContext servletContext;
...
InputStream is = servletContext.getResourceAsStream("/WEB-INF/test_model.js");
Note that, at least in GlassFish 3.1, the path had to be absolute, i.e., start with slash. More here: How do I use a properties file with jax-rs?

I had the same problem when I changed from Websphere 8.5 to WebSphere Liberty.
I utilized FileInputStream instead of getResourceAsStream(), because for some reason WebSphere Liberty can't locate the file in the WEB-INF folder.
The script was :
FileInputStream fis = new FileInputStream(getServletContext().getRealPath("/")
+ "\WEBINF\properties\myProperties.properties")
Note:
I used this script only for development.

I had a similar problem and I searched for the solution for quite a while:
It appears that the string parameter is case sensitive. So if your filename is abc.TXT but you search for abc.txt, eclipse will find it - the executable JAR file won't.

Related

Where to put file resources in Dynamic Web Project Tomcat? [duplicate]

I've got a file in my war/WEB-INF folder of my app engine project. I read in the FAQs that you can read a file from there in a servlet context. I don't know how to form the path to the resource though:
/war/WEB-INF/test/foo.txt
How would I construct my path to that resource to use with File(), just as it looks above?
Thanks
There's a couple ways of doing this. As long as the WAR file is expanded (a set of files instead of one .war file), you can use this API:
ServletContext context = getContext();
String fullPath = context.getRealPath("/WEB-INF/test/foo.txt");
http://tomcat.apache.org/tomcat-5.5-doc/servletapi/javax/servlet/ServletContext.html#getRealPath(java.lang.String)
That will get you the full system path to the resource you are looking for. However, that won't work if the Servlet Container never expands the WAR file (like Tomcat). What will work is using the ServletContext's getResource methods.
ServletContext context = getContext();
URL resourceUrl = context.getResource("/WEB-INF/test/foo.txt");
or alternatively if you just want the input stream:
InputStream resourceContent = context.getResourceAsStream("/WEB-INF/test/foo.txt");
http://tomcat.apache.org/tomcat-5.5-doc/servletapi/javax/servlet/ServletContext.html#getResource(java.lang.String)
The latter approach will work no matter what Servlet Container you use and where the application is installed. The former approach will only work if the WAR file is unzipped before deployment.
EDIT:
The getContext() method is obviously something you would have to implement. JSP pages make it available as the context field. In a servlet you get it from your ServletConfig which is passed into the servlet's init() method. If you store it at that time, you can get your ServletContext any time you want after that.
Now with Java EE 7 you can find the resource more easily with
InputStream resource = getServletContext().getResourceAsStream("/WEB-INF/my.json");
https://docs.oracle.com/javaee/7/api/javax/servlet/GenericServlet.html#getServletContext--
I know this is late, but this is how I normally do it,
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
InputStream stream = classLoader.getResourceAsStream("../test/foo.txt");

Not able to read file from jar in tomcat

I have a web application running under tomcat 7, and in one of the class, Im trying to read a file in one of the jar under WEB-INF/lib folder.
URL resourceURL = MyClass.class.getClassLoader().getResource("xml/xslt/master.xsl");
File xslfile = new File(resourceURL.getPath());
AssertUtil.assertTrue(xslfile.exists(),"xsl file not found");
Both MyClass and master.xsl resides in the same jar and there is no issue with packaging. But above snippet fails in the assertion statement as xslfile.exists returns false. The URL correctly resolves to the location of the file inside the jar as given below
file:/<MY_WEBAPP_LOCATION>/MyApp/WEB-INF/lib/MyComponent.jar!/xml/xslt/master.xsl
where MY_WEBAPP_LOCATION corresponds to the absolute path to my tomcat servers webapp directory.
But if I rewrite the code as below to read as inputstream, it works fine.
InputStream xslFile = MyClass.class.getClassLoader().getResourceAsStream("xml/xslt/master.xsl");
Can anyone explain what is preventing the creation of File from the jar resource, whereas the inputstream creation is working perfectly fine. Is there any additional permission settings needed from tomcat side, to read a file inside jar ?
EDIT: One more observation, if the file is placed under WEB-INF/classes, creation of File with above code works fine. Issue is only when it is placed in a jar under WEB-INF/lib
Be careful it seems that ClassLoader.getResource does not handle relative path.
See this.
GetResourceAsStream happens to take the path relative to the ClassLoader (and not the class !!). I think you're lucky enough that there are the same here.
If it is a Desktop application getResource() will work
But as this is a web application the resource needs to be extracted from Context , hence getResoruceAsStream()
It is not a permission problem, but the use of java.io.File API - in particular constructor http://docs.oracle.com/javase/7/docs/api/java/io/File.html#File%28java.lang.String%29
When you are constructing File object using
File xslfile = new File(resourceURL.getPath());
you are using java.io.File#File(String) method which expects an "abstract pathname". What is an acceptable/valid pathname is described by javadoc of the File class: http://docs.oracle.com/javase/7/docs/api/java/io/File.html
String value that your are getting from getPath() method:
file:/<MY_WEBAPP_LOCATION>/MyApp/WEB-INF/lib/MyComponent.jar!/xml/xslt/master.xsl
simply does not constitute a valid "abstract pathname" - it is a URL that is converted to a java.lang.String (and IMHO should be returned with URL scheme of "jar" and not "file"). Therefore a call to
isExist()
returns false as there is no file with such name on your disk.
On the other hand if the resource is outside of a jar (e.g. under WEB-INF/classes directory) resourceURL.getPath() will return a value that presents a valid abstract pathname as the resource in question is indeed a simple file.
When you use java.lang.ClassLoader#getResourceAsStream(java.lang.String) the method streams out the resource directly into a java.lang.InputStream and might not even use File class in its implementation.

File not being found in servlet, even though obtaining path via context.getRealPath?

Synopsis
Given the following (abridged) code that lives server-side on a servlet (Tomcat is the container). This is a GWT application, though that should be irrelevant (I think).
ServletContext context = getServletContext();
String dataFilePath= context.getRealPath("/WEB-INF/dir/dataFile.txt");
File dataFile = new File(dataFilePath);
TestCaseGenerator testCaseGenerator = new TestCaseGenerator(dataFile);
testCaseGenerator.generateTestCase();
TestCaseGenerator is a class from a jar in the project's war/WEB-INF/lib folder, that's been added to the GWT project as an external library.
The Problem
When testCaseGenerator.generateTestCase() gets executed, it's unable to use dataFile to create a new LineNumberReader(new FileReader(dataFile));, a FileNotFoundException gets thrown.
I've verified that the String value of dataFilePath is correct and contains the proper real path to the file on the server I need to read from, as well that dataFile isn't null. I've also verified that TestCaseGenerator runs just fine when called from a command line, outside of this GWT application.
I'm not sure why TestCaseGenerator isn't able to use the File object I pass it, considering I'm passing it the real file path of the file. I can come up with some alternative solutions to get around this issue, but now I'm genuinely curious why it isn't able to find the file.
Thanks in advance for any insight.
Solved
I foolishly neglected to include the dir/dataFile.txt in my build.xml's war target, so in fact the file wasn't being included in the war package, and thus never placed within the Tomcat container.
<include name="dir/**" />
And I also misunderstood what context.getRealPath("/WEB-INF/dir/dataFile.txt"); actual returns;. From ServletContext javadoc
Gets the real path corresponding to the given virtual path. For
example, if path is equal to /index.html, this method will return the
absolute file path on the server's filesystem to which a request of
the form http://://index.html would be
mapped, where corresponds to the context path of this
ServletContext.
So even though getRealPath returns a path value, it doesn't necessarily mean the file is at that actual path.

Tomcat: correct way to find a resource? [duplicate]

This question already has answers here:
How to find the working folder of a servlet based application in order to load resources
(3 answers)
Closed 7 years ago.
I've working on a big application deployed on a Tomcat server. There's only one .jsp page and all the UI is done using ext-js.
There are a lot of .java classes. In one of these class (which is performing validation), I'd like to add XML validation and to do this I need to access the .xsd file.
My problem is that I don't know how to cleanly find the path to my .xsd file.
I'll put the .xsd files in a repertory next to css/, images/, etc.
I know how to this in a crappy way: I call System.getProperty("user.home") and from there I find my webapp, the xsd/ folder, and the .xsd files.
But what is a "clean" way to do this?
Where am I supposed to find the path to my webapp (or to my webapp resources) and how am I supposed to pass this information down to the .java class that performs the validation?
For files in public web content the ServletContext#getRealPath() is indeed the way to go.
String relativeWebPath = "/path/to/file.xsd";
String absoluteDiskPath = getServletContext().getRealPath(relativeWebPath);
File file = new File(absoluteDiskPath);
// ...
However, I can't imagine that there is ever intent to serve the XSD file into the public and also the Java class which needs the XSD doesn't seem to be a servlet. So, I'd suggest to just put XSD file in the classpath and grab from there instead. Assuming that it's been placed in the package com.example.resources, you can load it from the classpath as follows:
String classpathLocation = "com/example/resources/file.xsd";
URL classpathResource = Thread.currentThread().getContextClassLoader().getResource(classpathLocation);
// Or:
InputStream input = Thread.currentThread().getContextClassLoader().getResourceAsStream(classpathLocation);
getServletContext().getRealPath("/") is what you need.
See here.

Reliable approach for loading resources in Java / JNLP

I'm writing a Java application that needs to access several resources in a .jar file that is run over JNLP.
While the application works fine in my development environment (Eclipse) it doesn't work when executed through JNLP, apparently because it can't find the resource file in the jar. I've checked the resource file and the resources are most definitely there.
I'm currently using code like:
someclass.getResourceAsStream("/resources/somefile.png");
What is the correct way to access a resource file in a .jar that will work with JNLP?
use : this.getClass().getClassLoader().getResourceAsStream(name)
example: myClass.getClass().getClassLoader().getResourceAsStream("resources/somefile.png")
two tips:
1 - use your own class that is in jar file. if used another class - for example Object - fails
2 - name i.e. resource must be without leading '/'
I got stuck for a while on a similar issue and the comment from #Devon_C_Miller saved me (once I saw it, after some time!), so I thought I'd recopy it here:
When you get a resource via a Class, the path is resolved relative to the class, unless you start it with a '/'. When you get it via a ClassLoader, it is always resolved as an absolute path and must not begin with a '/'.
In my case, I use the following syntax, for a file located in the JAR: /properties/config.properties:
//NO LEADING `/` EVEN IF IT IS AN ABSOLUTE PATH
private final static String CONFIG_FILE = "properties/config.properties";
InputStream resource = Configuration.class.getClassLoader().getResourceAsStream(CONFIG_FILE);

Categories