Java Shared Resources stored to wrong path - java

I have two projects that share a common resource folder. I use this command to access those files:
getClass().getClassLoader().getResource("myResources.xml")
This statement returns a path, which is not valid. In fact it returns:
project/shared-resources/target/classes/myResource.xml
but it should return
project/shared-resources/src/main/resource/myResource.xml
During the build process, all resources are copied to this target/classes path, so I am able to load those files, but changed are overwritten which is not wanted.
Any idea why this happens?

Using getClass().getClassLoader() will load resources from your class path.
project/shared-resources/src/main/
The above is your source path - no class files.
When you compile and run your application, classes are compiled to (and loaded from):
project/shared-resources/target/classes/
In your IDE (assuming you're using one), it's usually trivial to add a resource (your resource/myResource.xml file) into your build process, so that it's copied to the target into the same structure.
If / when your deploy / distribute your application, you'll need to do this as the src path won't typically be included in your jar, ear or war file etc.

Related

How import a file in a jar?

I have this project that it has this structure
Home
graphics
field.txt
example.java
I need to load field.txt in my example.java in jar and I use:
getClass().getClassLoader().getResource("field.txt").toUri();
but this code it give me "Null Pointer exception" .Anyone can help me?
example.class.getResource(“/graphics/field.txt“);
The class should belong to the same jar. For Class.getResource a relative “field.txt“ is possible (same package). With ClassLoader an absolute path for all classpaths is sought: “graphics/field.txt“.
To immediately read (never write) use getResourceAsStream or the URI of the getResource. One can use a Path on the URI. Files.copy(...).
One cannot at least should not) write a resource file (as it can reside in a jar jar:file://...; and jar might even be sealed; and resources might be cached by the jvm). Keep it as read-only template. Never File.
One technique is to create an application named directory in System.getProperty("user.home") and copy the template there.
To read the file it must be in classpath, you can put the file in the folder containing .class files or add it to the classpath with java -cp option.
The issue is not so much your code, but how you build and package your jar file. You will have to clarify how you are currently building your jar (using ant, maven, eclipse, etc ?).
Many articles will also advise you to separate out your resources from your source code (.java), and many IDE will support this separation direclty by allowing you to mark a folder as a resource folder. Even maven will allow you to customize this.
See following articles:
How to package resources in Jar properly
Using maven and netbeans, it is real simple: https://coderwall.com/p/d_cvrq/how-to-package-non-java-code-files-resources-in-a-jar-with-maven, or
use maven to pack javascript files in Jar?

Can't Access resource path, only the target path

I want to access the resource's form of my project "\src\main\resources" but for any reason I can only access the target classes.
Here is my code:
System.out.println(Main.class.getResourceAsStream("/123.txt")); // java.io.BufferedInputStream#66cd51c3
System.out.println(Main.class.getResource("/123.txt")); // file:/C:/Users/Raul/workspace/Serial/target/classes/123.txt
System.out.println(Thread.currentThread().getContextClassLoader().getResource("123.txt").getPath()); // /C:/Users/Raul/workspace/Serial/target/classes/123.txt
and here my Project Dirs:
The thing is, even if I delete all the files in the target/classes and run the code, the compiler will copy the files from "src/main/ressources" into "target/classes" and read them from there.
I want to access the resource's form of my project "\src\main\resources" but for any reason i can only access the target classes.
I think the question is answered by user #VGR. Just to clarify it in another words:
You put your resources in the /src/main/resources folder, and these resouces will be copied as is into the /target/classes folder when you build your project.
Example
src/main/resouces/123.txt -> target/classes/123.txt
src/main/resources/myresources/145.txt -> target/classes/myresources/145.txt
...
Now if you run the program inside of your IDE you'll observe the following:
System.out.println(Main.class.getResource("/123.txt"));
output: file:/C:/Users/Raul/workspace/Serial/target/classes/123.txt
System.out.println(Main.class.getResource("/myresources/145.txt"));
output: file:/C:/Users/Raul/workspace/Serial/target/classes/myresources/145.txt
But if you open the generated jar file you'll not see the target folder because the file 123.txt will be on the root of the jar file and the file 145.txt will be under the folder myresources/145.txt.
The folder target is just an output directory for the build tool and will not be packaged within your jar file.
Now to the following question:
the problem is that i dont know how to export the target classes to my jar, or how can I get "src/main/ressources" as return value.
To answer this question you have to look into your pom.xml file on the root of your project. There should be a <packaging>jar</packaging> entry in it. If that is so you create the jar file as follows:
Option 1: from the command line
mvn clean install
the jar file will be created and copied into the folder target.
Option 2: from within Eclipse (for example)
right click on the pom.xml > Run AS > Maven install
the jar file should also be generated and copied into the folder target.
Note: on your screenshot there are two jar files: core-0.0.1-SNAPSHOT.jar and Serial-0.0.1-SNAPSHOT.jar; remove them (mvn clean or right click > Run AS > Maven clean) before generating the jar file. The reason is Maven can only generate one jar file per Maven module / project, afaik.
You are seeing the intended behavior. A Java program is compiled into an executable form—meaning, .class files and resources. When other users run your program, they will not have access to the source, so your code should not assume your source tree will be available.
Simply put, your code is correct as is. Do not attempt to read the source tree. If you want target/classes to contain up-to-date files, rebuild your project.
A word of caution: Never use the getPath() method of URL to convert a URL to a file name. There are many characters which are not permitted in URLs, and those characters will be “percent-escaped” in order to conform to the URL specification; as a result, the path portion of a URL is not a valid filename! The only correct way to convert a URL to a file is Paths.get(url.toURI()). However, you should not even try to convert a resource to a file at all, because once you move on to packaging your programs in .jar files, your resources will not exist as regular files at all, only as entries in .jar files (which are actually just zip files with some Java-specific entries added).

class.getResource() is null though it is in classpath

I have a jar containing the main class of a project. This depends on several other jars that reside in a lib directory. One class of such a dependend jar loads a ressource "/Data/foo/bar/file.txt". But loading this file as ressource leads to null.
Here is the directory structure:
./main.jar
./lib/lib1.jar
./lib/lib2.jar
./lib/lib3.jar
./lib/runtimedata/Data/foo/bar/file.txt
This is the classpath of the manifest.mf of the main.jar:
lib/lib1.jar lib/lib2.jar lib/lib3.jar lib/runtimedata
I start the application via
java -jar main.jar
The lib2.jar contains a class that tries to load the file with
ThatClass.class.getResource("/Data/foo/bar/file.txt");
But that happens to be null. Why? lib/runtimedata is in the classpath.
I even tried to put the Data directory into lib/lib/runtimedata, in case the path is relative to the jar file containing the loading class. But that doesn't help.
What am I doing wrong here?
EDIT:
Running the application with
java -cp main.jar:lib/*.jar:lib/runtimedata my.package.Main
works correctly.
EDIT 2:
I cannot change that lib that does the resource loading. I am only using that lib. The only things I can change is the main.jar the classpath and the command line.
When you start the path with a "/", it's considered as absolute. Try ThatClass.class.getResource("/runtime/Data/foo/bar/file.txt");
Otherwise, if you cant't change the code, put the file on /Data/foo/bar/file.txt
In a development environment, this can sometimes happen when resources have not been processed during the build. Using Gradle and building your main JAR or main test JAR will depend on the compileJava tasks in your libs, but will not trigger their resources to be processed. You can see if this is happening by looking in your build dir to see if resources for your libs have been copied over. If they haven't been copied the resource loader won't find them at runtime.
If this is the problem, a full build will fix the issue and published JARs should always have their resources. But, it's nice to be able to trigger e.g. the test task for an individual module and know that it will always pull in everything it needs. If you have a library with essential resources that must always be present, you can force them to be processed in partial builds by adding this to the build.gradle of the library:
compileJava.dependsOn(processResources)

Load files from the source folder of a project using a loader from a different project

I have a utility project file that I've put code in for loading resource files. However, when I reference this project from a different one to use this loading code, the loader still uses its own src folder, instead of the src folder of the project referencing it.
I'm loading all my resources like this:
ClassLoader.class.getResourceAsStream(filepath)
...where filepath might be something like "/res/index.txt"
My first guess as to how to make this work would be to use a different class in the project I want to load from instead of the ClassLoader to get resources? What would the most elegant solution to this be?
I am using Netbeans, if that makes a difference.
If you use "/" in the beginning of filepath, it's gonna be resolved from the package root (it is clearly stated in the JavaDocs).
Try to make your build script copy the resources to the bin directory (IIRC NetBeans was compiling with Ant scripts, haven't used it for a while).

Eclipse project can not reference a file using relative paths

My file is located under the src directory. However, when I try to call it using "src/readme.txt" the file is not found.
In fact, it states that java is looking for "C:\Documents and settings\john\My Documents\Downloads\eclipse-win32\eclipse\coolCarsProject\src\readme.txt".
How do I fix this? I do not want to put in the absolute path all the time.
Do I need to fix the classpath, buildpath, or change the project root, etc? It is not at all obvious from the roughly 1000 settings in Eclipse for a newbie.
First, you have to decide if you want to load the file from the file system, or if the file will in fact be bundled with your application code.
If the former, then you should really think about how your application will be launched when actually deployed, because using a relative file path means that the program should always be started from the same location: a relative path is relative to the location from where the program is started (the current directory). If this is really what you want, then edit your launch configuration in Eclipse, go to the Arguments tab, and set the working directory you want. But the src directory is not where you should put this file, since this will copy the file to the target directory, along with the classes, that will probably be put in a jar once you'll deploy the application.
If the latter, then you should not treat the file as a file, but as a resource that is loaded by the ClassLoader, using ClassLoader.getResourceAsStream() (or Class.getResourceAsStream()). Read the javadoc of those methods to understand the path to pass. If you put the file directly under src, it will be copied by Eclipse to the target directory, along with your classes, in the default package. And you should thus use SomeClass.class.getResourceAsStream("/readme.txt") to load it.
Using paths relative to the current working directory is not a good idea in general, as it's often quite hard to establish what your current working directory will be. In Eclipse, it will be your project folder (unless you set it to something different in your launch configuration), in webapps it will be the webapp's root directory, in a command line app it could be anything.
Try this one:
String filePath = ".\\userFiles\\data.json";
where «.\» is a root for the Eclipse project, «userFiles» is a folder with the user's files inside of Eclipse project. Since we are talking about Windows OS, we have to use «\» and not «/» like in Linux, but the «\» is the reserved symbol, so we have to type «\\» (double backslash) to get the desired result.

Categories