I'm working in Maven web application (Java). I need to read a directory (for ex: mydirectory) in my webapp folder as follows:
File file = new File("path of my directory");
I just specify the hierarchy of folders in my application.
MyApplication->src->main->webapp->MyDirectory
But I'm going to write my Java code I the package as follows,
MyApplication->src->main->java->com->mypackage->myfile.java
From myfile.java I need to read the directory "MyDirectory" in webapp. As new File("path of the directory")
But I don't know how to specify the path of the directory here.
Try
ServletContext context = getServletContext();
InputStream is = context.getResourceAsStream("/MyDirectory/FileInThatDir.txt");
alternatively use getResource() instead of getResourceAsStream()
At runtime, there is no maven anymore (thank God!), and there is no directory anymore. All you have is a war file, and everything is either in the war file, or somewhere outside of the app, on the file system.
Use ServletContext.getResourceAsStream() to load a file from the webapp's context.
You haven't mentioned what technology/framework you use, but I suppose you're using at least Java servlets, because you mentioned it's a web application. So you can use ServletContext.getRealPath() to get the path in the filesystem:
String fullPath = getServletContext().getRealPath("/MyDirectory");
System.out.printf("real filesystem path: %s", fullPath);
Update:
Please note that JavaDoc of the method says:
The real path returned will be in a form appropriate to the computer and operating system on which the servlet container is running, including the proper path separators.
Resources inside the /META-INF/resources directories of JAR files bundled in the application's /WEB-INF/lib directory must be considered only if the container has unpacked them from their containing JAR file, in which case the path to the unpacked location must be returned.
This method returns null if the servlet container is unable to translate the given virtual path to a real path.
This means that the returned path:
is not portable (e.g. in Windows with \, in Linux/macOS with /, etc).
might be null, e.g. if the resource is virtually in memory, in a JAR file, or so.
Therefore: please follow my answer only with those caveats in mind, and better follow the other answers using ServletContext.getResourceAsStream()
I couldn't access the servlet context since the service where i need to read data from the webapp folder is not aware of the current servlet context.
Anyone who is using Spring can never the less access the webapp folder by simply implementing the ResourceLoaderAware Interface provided by the spring framework.
public class SomeService implements ResourceLoaderAware {
private ResourceLoader resourceLoader;
#Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
public readFromWebappFolder() {
Resource resource = resourceLoader.getResource("path/to/file/in/webappFolder");
}
}
Related
Environment: Ubuntu 18 + Spring boot 2.0 + JDK 11
It performs correctly when the application runs in IntelliJ, but it doesn't when reading the file after Spring boot maven plugin packaging file.
PS: The file indeed could be found in the packaged jar file!
java.io.FileNotFoundException: class path resource [jmxremote.password]
cannot be resolved to absolute file path because it does not reside in the
file system: jar:file:/home/XXX/YYY/target/YYY-1.0-Final.jar!/BOOT-
INF/classes!/jmxremote.password
You are most likely attempting to use java.io classes to load a class path resource. This won't work, the java.io classes are designed only for file system operations.
Either extract jmxremote.password outside of the JAR or use the regular InputStream to access it as a class path resource e.g. by using Class.getResourceAsStream():
try (InputStream in : getClass().getResourceAsStream("/jmxremote.password")) {
// read input
}
TL;DR
In the Spring Framework environment focus on using Spring utility tooling for handling resources (like the ResourceUtils class) which nicely encapsulate lower-level, operating system dependent IO operations. The ResourceUtils already contains multiple traps to figure out if the project you are running is exploded (run in IDE) or packaged (inside a JAR file).
The answer provided by Karol seems the easiest and is relatively bullet-proof, until you need a certain level of flexibility to specify file location (inside a jar file but with the possibility to define it externally and provide somewhere in the file system). Then the approach with getResourceAsStream() method won't work.
Standard Java IO (java.nio) is using FileSystemProvider classes to delegate IO operations (like creating, reading and deleting files).
A provider is identified by a URI scheme. The default provider is identified by the URI scheme "file." It creates the FileSystem that provides access to the file systems accessible to the Java virtual machine. The FileSystems class defines how file system providers are located and loaded.
So, if your file is somewhere on the filesystem, there are no issues, and everything works fine. Technically, the URL returned by Application.class.getResource("").toURI() starts with file:// and contains a valid filesystem path.
Having said that, when your file "land" inside a jar file, the Application.class.getResource("").toURI() returns something more like file://{jar-location}!/ (mind the exclamation mark), which is not a valid file schema path and Java doesn't know how to handle it. An additional file system provider needs registering.
FileSystems.newFileSystem(uri, emptyMap());
Java figures out (based on URI) the scheme and registers a new file system. From now on, standard java.nio file operations can be used.
For example, if you have some files in a /webapp folder which can (but don't need to) be inside a jar file and you'd like to list them.
// Load zip specific filesystem provider when run from inside a fat-jar
URI uri = Application.class.getResource("").toURI();
if (uri.toString().contains("!")) {
FileSystems.newFileSystem(uri, emptyMap());
}
URI rootFolder = Application.class.getResource("/webapp").toURI();
List<Path> banners = Files.list(Paths.get(rootFolder))
.collect(Collectors.toList());
Random rand = new Random();
Path path = banners.get(rand.nextInt(banners.size()));
log.info("Random image: {}", path.getFileName());
byte[] bytes = Files.readAllBytes(path);
Installation of a new file system provider is global and should be done only once.
Suppose I had a directory containing resource files stored somewhere within the "src" source directory, containing things like templates, config files, etc.
I'm aware that from a Servlet I can access files by name like:
File file = new File(ServletContact.getResource("some/namespace/filename.txt").getPath());
And from a non-Servlet I can do:
File file = new File(Object.class.getResource("some/namespace/filename.txt").getPath());
But the problem is that I have code that needs to access these resource files and can be run independent of the runtime environment. e.g. Some code uses templates from within a servlet (under Tomcat 7). Other code runs as a Quartz background job and works with templates. If I try the Object.class.getResource() method in a Tomcat servlet, it returns null.
How can I access resources files in a safe way regardless of runtime environment, app engine, etc.?
To read file from classpath you can use:
getClass().getClassLoader().getResourceAsStream("path/to/resource");
Also there is simple and useful Spring utility ClassPathResource class:
Resource resource = new ClassPathResource("path/to/resource");
I would use any class (e.g. domain class) from your project, use getClassLoader() or getContextClassloader() and provide the path to your resource. Should work.
I've just been getting started setting up a web service with jax-rs running on Tomcat. Is there a way to bundle a properties file with my java project (in eclipse) so that I can read properties out of it at runtime? Also if it's possible, where would be the best location to put it (so that it couldn't be seen via a url), WebContent, WEB-INF, etc?
Thanks.
Several options:
Option 1: You can put it under your classpath (in Eclipse put it under and source folder), so you can access it via the Classloader: MyClass.class.getResourceAsStream("myproperties.properites")
Pay attention that MyClass must also be in the same source folder (actually it's a bit more complex, it must be in the same classloader hierarchy, but any class from the same folder will do the job)
Option 2: Put it in WEB-INF folder. It's a preferred option, since you don't need to deal with the classpath. You'll need a ServletContext to access it: javax.servlet.ServletContext.getResourceAsStream("WEB-INF/myproperties.properites")
In jax-rs you can obtain the ServletContext using the #Context annotation in any registered resource or provider.
For GlassFish 3.1 users, I was able to get both of Tarlog's options working, but I had to use the file's absolute path. For Option 1 I put the file in the Source Packages folder in NetBeans, which I could then access via:
InputStream is = TestResource.class.getResourceAsStream("/test_model.js");
For Option 2 I put the file under WEB-INF and used:
#Context ServletContext servletContext;
InputStream is = servletContext.getResourceAsStream("/WEB-INF/test_model.js");
Without the leading slash the result was null. HTH
I would like to create an xml file and store in a folder within my spring Mvc web application.
I can get the root of my application with request.getContextPath()
but
how do i get the application's relative path so it will work on any machine indipendently by the location of the application's folder?
Like C:/folder/folder/MYAPPLICATIONROOTFOLDER
You want to do this.
First, you need to get the ServletContext. I don't know how this is done in Spring MVC, but it's there somewhere.
Then you can do:
ServletContext ctx = getServletContextFromSpringSomehow();
String path = ctx.getRealPath("/folder/filename.txt");
FileWriter fw = new FileWriter(path);
The key here is ServletContext.getRealPath. It gives you the local file system path of a resource from within your webapp. Observer that you use "/" here, as it's a URL, not a file name. The container will give you a valid file name in return. Note, this only works if your container explodes your WAR, or you deploy an exploded WAR. If the WAR is NOT exploded, you will get a null back from the container.
Also note, this WILL work for non-existent files. The container does not check for the actual existence of the file. But it will be up to you to actually create any missing intermediate directories, etc.
Finally, of course, that even if you get a file path back, doesn't mean you can actually write to that path. That's a OS permission issue outside of the scope of the container.
One solution is to bundle the XML with the clases in the JAR/WAR and then use the getResourceAsStream() to leverage the ClassLoader to locate the file.
If I put the file foo.xml with the classes in com/stackoverflow/example, I could then locate the resources from objects in that bundle with
InputStream is = MyClass.getResourceAsStream( "com/stackoverflow/example" );
and from here process the file with a XML parser or whatever else you wanted to do to read the file.
I want to read a file from a java web application. I don't want to give the absolute path of the file. I just want to put the file in some directory of my web application.
Or
It can be placed along with .war file (packaged web application).
What relative path to give for the file. I tried ./filename.csv but it didn't work.
========Updated========
I will deliver a WAR file (packaged web application) to my client. This web application will read a file (lets say SuppliedFile.csv) which will be copied to the server by the client. So I need a mechanism (that will work irrespective of whether the application server will unpak the WAR or not) so that web application can read that file.
Note:
I am not using the SuppliedFile.csv in a servlet... I am using it in a plain Java class...
Do you really need to load it from a file? If you place it along your classes (in WEB-INF/classes) you can get an InputStream to it using the class loader:
InputStream csv =
SomeClassInTheSamePackage.class.getResourceAsStream("filename.csv");
You may be able to simply access a pre-arranged file path on the system. This is preferable since files added to the webapp directory might be lost or the webapp may not be unpacked depending on system configuration.
In our server, we define a system property set in the App Server's JVM which points to the "home directory" for our app's external data. Of course this requires modification of the App Server's configuration (-DAPP_HOME=... added to JVM_OPTS at startup), we do it mainly to ease testing of code run outside the context of an App Server.
You could just as easily retrieve a path from the servlet config:
<web-app>
<context-param>
<param-name>MyAppHome</param-name>
<param-value>/usr/share/myapp</param-value>
</context-param>
...
</web-app>
Then retrieve this path and use it as the base path to read the file supplied by the client.
public class MyAppConfig implements ServletContextListener {
// NOTE: static references are not a great idea, shown here for simplicity
static File appHome;
static File customerDataFile;
public void contextInitialized(ServletContextEvent e) {
appHome = new File(e.getServletContext().getInitParameter("MyAppHome"));
File customerDataFile = new File(appHome, "SuppliedFile.csv");
}
}
class DataProcessor {
public void processData() {
File dataFile = MyAppConfig.customerDataFile;
// ...
}
}
As I mentioned the most likely problem you'll encounter is security restrictions. Nothing guarantees webapps can ready any files above their webapp root. But there are generally simple methods for granting exceptions for specific paths to specific webapps.
Regardless of the code in which you then need to access this file, since you are running within a web application you are guaranteed this is initialized first, and can stash it's value somewhere convenient for the rest of your code to refer to, as in my example or better yet, just simply pass the path as a paramete to the code which needs it.
If you have a path for that file in the web server, you can get the real path in the server's file system using ServletContext.getRealPath(). Note that it is not guaranteed to work in every container (as a container is not required to unpack the WAR file and store the content in the file system - most do though). And I guess it won't work with files in /WEB-INF, as they don't have a virtual path.
The alternative would be to use ServletContext.getResource() which returns a URI. This URI may be a 'file:' URL, but there's no guarantee for that.
Many popular Java webapps, including Jenkins and Nexus, use this mechanism:
Optionally, check a servlet context-param / init-param. This allows configuring multiple webapp instances per servlet container, using context.xml which can be done by modifying the WAR or by changing server settings (in case of Tomcat).
Check an environment variable (using System.getenv), if it is set, then use that folder as your application data folder. e.g. Jenkins uses JENKINS_HOME and Nexus uses PLEXUS_NEXUS_WORK. This allows flexible configuration without any changes to WAR.
Otherwise, use a subfolder inside user's home folder, e.g. $HOME/.yourapp. In Java code this will be:
final File appFolder = new File(System.getProperty("user.home"), ".yourapp");
The alternative would be to use ServletContext.getResource() which returns a URI. This URI
may be a 'file:' URL, but there's no guarantee for that.
You don't need it to be a file:... URL. You just need it to be a URL that your JVM can
read--and it will be.
there is another way,
if you are using a container like Tomcat :
String textPath = "http://localhost:8080/NameOfWebapp/resources/images/file.txt";