This is driving me crazy. I have a simple eclipse project with a src folder and a class in it. But I can't seem to get getResource to find it. What am I doing wrong?
import java.net.URL;
public class ContextTest {
public static void main(String[] args) {
URL url = ContextTest.class.getResource("/src/ContextTest.java");
System.out.println(url);
}
}
If I right-click on the class name, the path is /TestsProject/src/ContextTest.java and the default classpath according to the Classpath tab in Run Configurations is TestProject.
It doesn't work with /bin/ContextTest.java , /ContextTest.java , ContextTest.java either.
When you load resources using ContextTest.class.getResource("/....") the leading / is translated as an absolute path. Here absolute means from your root package (i.e. the default package).
In Eclipse the root package is considered the one that is under the src folder. Your compiled classes will be placed under bin folder and if you create a jar you will see that your root package is not the src or bin folders but whatever folders are inside it. (for example com).
So the correct way to load a resource using a class absolute path would be ContextTest.class.getResource("/ContextTest.java");. If the file ContextTest.java is in the root package of wherever your compiled classes are, then it will be found and returned.
I hope this clears the picture.
Update: From the comments below it is not clear what you are trying to do. When you use getResource() you are not loading a file but a resource from the classpath. This would correctly find the resource even if your files were inside a jar file. So for your above example to work the file you are trying to load as a resource should be in the classpath (i.e. under bin folder since this is the root of your classpath when you execute from inside Eclipse). If you are trying to load a file outside of your classpath then don't try to load a resource, you could use File instead.
Resources accessed via getResource() must be on the classpath. Your Java files will be compiled and placed on the classpath. The compiled .java file will be given an extension of .class.
Try
URL url = ContextTest.class.getResource("ContextTest.class");
Related
I am trying to get a properties file from /src/main/resources/properties/ but for some reason the following code returns the path of target classes instead of src files. Can you please help?
System.out.println(PropTest.class.getResource("/properties/app.properties"));
System.out.println(PropTest.class.getClassLoader().getResource("properties/app.properties"));
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
System.out.println(classloader.getResource("properties/app.properties"));
PropTest prop=new PropTest();
System.out.println(prop.getClass().getResource("/properties/app.properties"));
Each line gives the same output which is:
file:/C:/Users/b./eclipse-workspace/ordermonitoring/target/classes/properties/app.properties
file:/C:/Users/b./eclipse-workspace/ordermonitoring/target/classes/properties/app.properties
file:/C:/Users/b./eclipse-workspace/ordermonitoring/target/classes/properties/app.properties
file:/C:/Users/b./eclipse-workspace/ordermonitoring/target/classes/properties/app.properties
The behavior is correct. The resources will be loaded from class path. There wont be any src folder at runtime. What you can do is make the /src/main/resources as a source folder (if you are not using maven) so that the properties will be copied to target folder.
This is the expected behaviour. For maven projects, while running, project is build and is kept in target folder always. you can also change this folder by some configuration. From this target folder, your application runs and thus your path shown in classloader.getResource() method. If you are building a jar , then your resources will be inside the jar and is always available. So classloader.getResource() will be working fine always.
I have a Maven project. My entire code is in the folder {PROJECT_ROOT}/src/main/java. When I write the code:
InputStream input = VertxApp.class.getClassLoader().getResourceAsStream("file.txt");
String result = getStringFromInputStream(input);
System.out.println(result);
I see that the code looks for the file named "file.txt" in the folder:
{PROJECT_ROOT}/src/main/resources.
My question is why. Why doesn't it look for files in {PROJECT_ROOT}/src/main/java or in ${PROJECT_ROOT} for example?
Most Maven projects follow the structure of
src/
main/
java/
resources/
You're intended to keep your non-code resources separate from your code. The getResourceAsStream method assumes this standard is followed, so it looks for your resource starting from the resources/ directory.
See Why are project layout resources are kept separate from Java sources? for some more detailed thoughts.
When you build a maven project or run it from an IDE supporting maven, the java files from src/main/java are compiled to class files and put in PROJECT_ROOT/target/classes.
The files from src/main/resources are copied to PROJECT_ROOT/target/classes as well.
When you call VertxApp.class.getClassLoader().getResourceAsStream("file.txt") you get the classloader for the VertxApp class and this classloader will try to load the given resource from the path where the class was loaded from.
If your VertxAppclass is in the top package, the the class file will be in target/classesand the resource will be searched there as well as you specify a relative path of "file.txt", therefore you must put it in src/main/resources.
If the VertxAppclass is for example in a package named mypackagethen the class file would be in target/classes/mypackage and you should have the file in src/main/resources/mypackage so that it ends up in target/classes/mypackageas well.
If you have the VertxAppclass in a package but want to keep the file in src/main/resources(without a subdirectory), you must reference it as an absolute path like this:
VertxApp.class.getClassLoader().getResourceAsStream("/file.txt")
I have a runnable jar file which is not able to access my resources which reside outside of the default src directory. Based on my understanding from What is the difference between Class.getResource() and ClassLoader.getResource(), I should be able to access root/res/img/img1.png (see folder setup below) by using the following getResourceFile function:
public class Foo {
private static final ClassLoader CLASS_LOADER = Foo.class.getClassLoader();
public static File getResourceFile(String relativePath) {
// Since I'm using getClassLoader, the path will resolve starting from
// the root of the classpath and it'll take an absolute resource name
// usage: getResourceFile("img/img1.png")
// result: Exception in thread "main" java.lang.NullPointerException
return new File(CLASS_LOADER.getResource(relativePath).getFile());
}
}
folder setup:
root/
src/
foo/
bar/
res/
img/
img1.png
audio/
audio1.wav
The problem arises when I try to execute the jar executable itself. However, the strange thing is that I was not able to replicate this through eclipse IDE which was actually able to resolve the path correctly. I have added the resource directory to the build path via (Project -> Properties -> Java Build Path -> Add Folder) so Java should be able to find the resource folder at runtime.
Is there something I'm missing in terms of generating the jar file? When unpacking the jar file everything seems to be in order with the img and audio directories being in the root (given the above initial folder setup):
foo/
/bar
img/
img1.png
audio/
audio1.wav
Files can only be used to represent actual files in your filesystem. And once you package your files into a JAR, the resource (img/img1.png) is not a file anymore, but an entry in the JAR file. As long as you use the folder structure from within Eclipse, the resources are individual files so everything is fine.
Try this:
System.out.println(CLASS_LOADER.getResource(relativePath));
It will print a URL, but it will not be a valid path to a file in your file system, but to an entry within the JAR file.
Usually, you will only want to read a resource. In that case, use getResourceAsStream() to open an InputStream.
I have a jav aproject which is build through ant. It write the class files to output/classes/com/... path. One of my java classes needs input stream read from a file that is in a folder one level above output folder. Looks like if copy the file to the package folder under outptu/classes, it seems to work. But I do not want to palce my config file in output folder as it will be cleaned when I do ant clean. I want it to find it look above the output folder, in config folder and load it.
public static final String CONFIG_FILE="/../../../../../../../Config.txt";
public static ConfigObj getConfigObj() throws IOException {
InputStream i=ConfigLoader.class.getResourceAsStream(CONFIG_FILE);
...
I want to know when I want to give raltivepath, what should it be relative to. I tried looking up , it says relative to classloader. What is classloader in this case? Is it output/classes/com....../config folder where my ConfigLoader.class lives?
The problem is that getResourceAsStream() will only load resources from the classpath. I guess you only have output/classes on your classpath, so you will never be able to load the config file via getResourceAsStream() if it's outside that directory. Use a File with an absolut path pointing to the file, or place it in your classpath.
Lots of confusion in this topic. Several Questions have been asked. Things still seem unclear.
ClassLoader, Absolute File Paths etc etc
Suppose I have a project directory structure as,
MyProject--
--dist
--lib
--src
--test
I have a resource say "txtfile.txt" in "lib/txt" directory. I want to access it in a system independent way. I need the absolute path of the project.
So I can code the path as abspath+"/lib/Dictionary/txtfile.txt"
Suppose I do this
java.io.File file = new java.io.File(""); //Dummy file
String abspath=file.getAbsolutePath();
I get the current working directory which is not necessarily project root.
Suppose I execute the final 'prj.jar' from the 'dist' folder which also contains "lib/txt/txtfile.txt" directory structure and resource,It should work here too. I should absolute path of dist folder.
Hope the problem is clear.
You should really be using getResource() or getResourceAsStream() using your class loader for this sort of thing. In particular, these methods use your ClassLoader to determine the search context for resources within your project.
Specify something like getClass().getResource("lib/txtfile.txt") in order to pick up the text file.
To clarify: instead of thinking about how to get the path of the resource you ought to be thinking about getting the resource -- in this case a file in a directory somewhere (possibly inside your JAR). It's not necessary to know some absolute path in this case, only some URL to get at the file, and the ClassLoader will return this URL for you. If you want to open a stream to the file you can do this directly without messing around with a URL using getResourceAsStream.
The resources you're trying to access through the ClassLoader need to be on the Class-Path (configured in the Manifest of your JAR file). This is critical! The ClassLoader uses the Class-Path to find the resources, so if you don't provide enough context in the Class-Path it won't be able to find anything. If you add . the ClassLoader should resolve anything inside or outside of the JAR depending on how you refer to the resource, though you can certainly be more specific.
Referring to the resource prefixed with a . will cause the ClassLoader to also look for files outside of the JAR, while not prefixing the resource path with a period will direct the ClassLoader to look only inside the JAR file.
That means if you have some file inside the JAR in a directory lib with name foo.txt and you want to get the resource then you'd run getResource("lib/foo.txt");
If the same resource were outside the JAR you'd run getResource("./lib/foo.txt");
First, make sure the lib directory is in your classpath. You can do this by adding the command line parameter in your startup script:
$JAVA_HOME/bin/java -classpath .:lib com.example.MyMainClass
save this as MyProject/start.sh or any os dependent script.
Then you can access the textfile.txt (as rightly mentioned by Mark) as:
// if you want this as a File
URL res = getClass().getClassLoader().getResource("text/textfile.txt");
File f = new File(res.getFile());
// As InputStream
InputStream in = getClass().getClassLoader()
.getResourceAsStream("text/textfile.txt");
#Mark is correct. That is by far the simplest and most robust approach.
However, if you really have to have a File, then your best bet is to try the following:
turn the contents of the System property "java.class.path" into a list of pathnames,
identify the JAR pathname in the list based on its filename,
figure out what "../.." is relative to the JAR pathname to give you the "project" directory, and
build your target path relative to the project directory.
Another alternative is to embed the project directory name in a wrapper script and set it as a system property using a -D option. It is also possible to have a wrapper script figure out its own absolute pathname; e.g. using whence.