What Does Servletcontext.Getrealpath("/") Mean and When Should I Use It

What does servletcontext.getRealPath(/) mean and when should I use it

Introduction

The ServletContext#getRealPath() is intented to convert a web content path (the path in the expanded WAR folder structure on the server's disk file system) to an absolute disk file system path.

The "/" represents the web content root. I.e. it represents the web folder as in the below project structure:

YourWebProject
|-- src
| :
|
|-- web
| |-- META-INF
| | `-- MANIFEST.MF
| |-- WEB-INF
| | `-- web.xml
| |-- index.jsp
| `-- login.jsp
:

So, passing the "/" to getRealPath() would return you the absolute disk file system path of the /web folder of the expanded WAR file of the project. Something like /path/to/server/work/folder/some.war/ which you should be able to further use in File or FileInputStream.

Note that most starters don't seem to see/realize that you can actually pass the whole web content path to it and that they often use

String absolutePathToIndexJSP = servletContext.getRealPath("/") + "index.jsp"; // Wrong!

or even

String absolutePathToIndexJSP = servletContext.getRealPath("") + "index.jsp"; // Wronger!

instead of

String absolutePathToIndexJSP = servletContext.getRealPath("/index.jsp"); // Right!

Don't ever write files in there

Also note that even though you can write new files into it using FileOutputStream, all changes (e.g. new files or edited files) will get lost whenever the WAR is redeployed; with the simple reason that all those changes are not contained in the original WAR file. So all starters who are attempting to save uploaded files in there are doing it wrong.

Moreover, getRealPath() will always return null or a completely unexpected path when the server isn't configured to expand the WAR file into the disk file system, but instead into e.g. memory as a virtual file system.

getRealPath() is unportable; you'd better never use it

Use getRealPath() carefully. There are actually no sensible real world use cases for it. Based on my 20 years of Java EE experience, there has always been another way which is much better and more portable than getRealPath().

If all you actually need is to get an InputStream of the web resource, better use ServletContext#getResourceAsStream() instead, this will work regardless of the way how the WAR is expanded. So, if you for example want an InputStream of index.jsp, then do not do:

InputStream input = new FileInputStream(servletContext.getRealPath("/index.jsp")); // Wrong!

But instead do:

InputStream input = servletContext.getResourceAsStream("/index.jsp"); // Right!

Or if you intend to obtain a list of all available web resource paths, use ServletContext#getResourcePaths() instead.

Set<String> resourcePaths = servletContext.getResourcePaths("/");

You can obtain an individual resource as URL via ServletContext#getResource(). This will return null when the resource does not exist.

URL resource = servletContext.getResource(path);

Or if you intend to save an uploaded file, or create a temporary file, then see the below "See also" links.

See also:

  • getResourceAsStream() vs FileInputStream
  • Recommended way to save uploaded files in a servlet application
  • Simple ways to keep data on redeployment of Java EE 7 web application

ServletContext getRealPath method - what is a virtual path?

ServletContext.getRealPath(String s) returns the real file system path. The input string is interpreted relative your Web Applications' Context Path.

In e.g. eclipse this is typically the folder WebContent inside your Web Application project (it is possible to customize that). After building a WAR file out of the project, you'll realize that the WebContent folder disappeared, so on the server the input string is interpreted relative to the WAR files' folder (or the .war library - this depends whether you explode the WAR during deployment or not).

A note on security

This method should (not must) only be used in case you want to access a file on the serverside. Typical scenario is parsing a configuration file during startup. Just keep in mind to never let the caller of your application know the real file system path of a given resource.

ServletContext().getRealPath() returns path not ending with /

I Fixed the issue.

The issue was, I didn't put '/' before "resources".

ServletContext.getRealPath("")+"/resources"

Context getRealPath() for non-existent file

I have taken the time to dive into Tomcat source to find the cause for this. It turns out that getRealPath, in addition to retrieving the system path for a given virtual path, also works a bit with the Tomcat cache.

NOTE:

I know that my file separator usage is not good, but Tomcat is smart enough to validate the above call to produce /bluesModified.wav. So even if I call it like @rickz mentioned in the comments, the result would be the same and therefore that was not the issue.

The issues I had with being unable to reference the file in the case of the following call

context.getRealPath("/" + "\\bluesModified.wav")

was the fact that in this case we are passing the file path to the method, while in the case that works we are passing in the directory path.

What happens is that the call to getRealPath() first checks the cache for the existence of the resource identified by the webapppath /bluesModified.wav. Since it does not exist at the moment of the call, Tomcat will create an instance of the EmptyResource class which is basically a wrapper around File class and represents a file that does not exist, and it will then store the reference to this file in its cache.

The issue here is that even though I create a file that will have the correct virtual path Tomcat will still have that empty resource representing a non existent file in its cache. In other words, if I reference the file from the client side like so

http://localhost:8080/AudioSimulator/bluesModified.wav

Tomcat will return the cached resource that represents the empty file, which actually means a 404 to the client even though the file exists.

Waiting for 5 seconds, which is the time to live of Tomcat cache entries, and then trying to reference the file will revalidate the cache entry and produce a FileResource instead of EmptyResource in which case the referencing will work normally.

It works in this case

context.getRealPath("/") + "\\bluesModified.wav"

since the path that is getting cached is a directory and the file name is simply concatenated. So the string I have here is just an absolute path to the file I am going to create with no cache entries colliding with it.

My mistake was assuming that getRealPath() is just some "pure" method that will return a string I can use to create files while in fact it has a bit of side effects. These side effects are not documented and even though I might have done some things incorrectly the bottom line is this method is not that predictable to use when doing File IO stuff.

Does ServletContext.getRealPath() work with web fragments?

Yes, getResourcesAsStream() always works. But getRealPath() doesn't.

Answer: Don't try to use getRealPath() together with web fragments.

How do I get real path as string in Grails

I was unable to find a solution that worked both locally and when deployed in a container. I ended up using this workaround instead to get the path depending on which environment the code is running in:

def path
if (Environment.current == Environment.DEVELOPMENT) {
path = java.nio.file.FileSystems.default.getPath("someSource").toAbsolutePath().toString()
} else {
path = ServletContextHolder.servletContext.getRealPath("/someSource")
}


Related Topics



Leave a reply



Submit