Java jar can't access resources - java

I need to execute a jar file which uses some files located in some subfolders.
For example the directory tree can be like this:
jar_root/
├── executable.jar
├── folder1/
│ └── required_file1.txt
│
├── folder2/
│ └── required_file2.txt
│
├── other_folder/
│ └── ...
└── other_file.txt
In this example executable.jar needs to access required_file1 and required_file2.
I need to execute the jar from another directory, so I tried this command:
java -cp /path/to/jar_root/ -jar /path/to/jar_root/executable.jar <options>
But what I got is a FileNotFoundException on required_file1 (I guess the same Exception will be raised for required_file2)
How can I make the jar work?
Note that I cannot modify the jar, so I can't use getResourceAsStream, as suggested by this (and other) answer(s).

It depends on how the code in the jar tries to access the files. If by relative path, that can only work if you start the program from the appropriate working directory, for example:
cd /path/to/jar_root/
java -jar executable.jar <options>
An alternative is to reference the files by absolute path, or relative from classpath instead of filesystem path.

Related

"ClassNotFoundException" while trying to run .jar file

I have a .jar that I built following the Oracle docs, using jar cfm hangman.jar Manifest.txt src/classes/app/Main.class. The manifest.txt file contains Main-Class as classes.app.Main, telling where my Main class is. When executed, ClassNotFoundException is thrown, saying it couldn't find classes.app.Main. I need help trying to understand what's wrong here. Is it the main class or maybe a missing classpath?
Here's the project tree:
.
├── hangman.jar
├── Manifest.txt
├── README.md
└── src
├── app
│   ├── Main.java
│   ├── Player.java
│   ├── Players.java
│   ├── Play.java
│   ├── Themes.java
│   ├── Word.java
│   └── Words.java
└── classes
└── app
├── Main.class
├── Play.class
├── Player.class
├── Players.class
├── Themes.class
├── Word.class
└── Words.class
You don't show the code, but it is extremely likely that the package for your class is just app not classes.app, and classes is only a directory name to contain the class files, not actually part of the package hierarchy. The name of a class file entry in a jar, OR the name of a class file relative to a classpath directory, must be exactly a directory path equal to the package hierarchy (if any) plus the class name and the suffix .class, with nothing added or removed. This means your jar should be created by going to the classes directory and then adding the file(s) relative to that directory:
jar cfm hangman.jar Manifest.txt -C classes app/Main.class
and the Main-class entry in the manifest should be app.Main. If you only need main-class in the manifest and nothing else (except version, IIRC), you can have jar create it for you:
jar cfe hangman.jar app.Main -C classes app/Main.class
Also I note that there are other classes in your source tree. If these classes are called or referenced from the Main class, directly or indirectly (i.e. nested), they must also be in the jar. You probably want to use app/* instead, although it is possible you want or even need to be more selective.
Meta: I thought this was covered in the standard tutorial, but although most of the pieces are there they aren't really pulled together anyplace I could find and refer to.

How does JPMS knows which packages belong to which modules?

I am trying to get a better understanding of how the new java module system works, especially when it comes to bundling together java packages to their respective modules.
I could not find a way of asking this question in an easy to understand way without tying it to a specific example.
If I have the following project structure:
.
└── src
└── main
└── java
├── module-info.java
└── org
└── lb
└── app
└── App.java
where module-info.java is:
module lb.module {}
and App.java is:
package org.lb.app;
public class App {
public static void main (String[] args) {
System.out.println("Hello, world!");
}
}
and then I run the command from the . directory:
javac -d build/classes $(find src/main/ -name "*.java")
which gives me the following result:
.
├── build
│   └── classes
│   ├── module-info.class
│   └── org
│   └── lb
│   └── app
│   └── App.class
└── src
└── ...
and finally I run the command:
java --module-path build/classes/ --module lb.module/org.lb.app.App
My questions are:
How does the javac tool knows that module-info.class should be in the root directory folder build/classes if there is no "package information" (e.g. like there are in normal java files), and not, for instance in a folder that mimics the original location (e.g. build/classes/src/main/java/module-info.class
I did not expect it to work, but it does. How does the JVM knows that the org.lb.app package belongs to the lb.module module? I purposefully "misnamed" the module, making it not have same name as the directory that contains it, and also did not export the package. It seems obvious for a human reader, but I want to understand what the java program assumes in order to bundle these two together.
Thank you.

How to copy folder from .jar file using shell script

I have jar file ex: sample.jar under this jar file there is a folder structure ex: "environment/xyz.properties" and "environment/abc.properties".
My Requirement: I need to copy entire "environment" folder with all property files and past in some other (ex: /tmp/environment)location using shell script.
Please help how to do copy folder from .jar using shell script.
struct
├── a
│   └── file_a.txt
├── b
│   └── file_b.txt
└── c
└── file_c.txt
Create jar
jar cf struct.jar ./struct
Extract dir
jar xf struct.jar struct/a
After file is extracted you can do whatever you like:
jar xf struct.jar struct/a
cp -r struct/a /tmp/environment
From what I understand you want to copy a directory in a shell,
so you type
cp -R /path/to/directory /path/to/other/location/

Open a file from the src directory (Java)

I've written a short documentation for my Java program. When clicking on the menu Help -> Documentation the default PDF reader of the OS should open the documentation.pdf.
I'm trying to open the PDF which is located in the directory src/doc with Desktop.getDesktop().open(new File("doc/documentation.pdf")); in Controller.java.
However, Java does not find the file. When I open the icon for the program with primaryStage.getIcons().add(new Image("icon/icon_512x512.png")); it works perfectly in Main.java.
Here you can see layout of my IntelliJ project.
src
├── META-INF
├── de
│   └── myapp
│   ├── model
│ │ └── *.java
│   ├── view
│ │ └── *.java
│ ├── Main.java
│   └── Controller.java
├── doc
│ └── documentation.pdf
└── icon
└── icon_512x512.png
My stack
IntelliJ 2016.2
Java 1.8.0_77
It works with new Image("icon/icon_512x512.png") because internally it gets is from the context ClassLoader which is not the case of new File("doc/documentation.pdf") that gets it from the user working directory in case of a relative path, so you could simply apply the same logic.
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
URL resource = contextClassLoader.getResource("doc/documentation.pdf");
Desktop.getDesktop().open(new File(resource.toURI()));
3-rd party applications can not access src dir in your application, in case, when your app assemble in jar archive. You should place your file separately from src.
Of course, java find icons, because it's java API.
You can access any resources in src folder through follow methods:
URL url = getClass().getResource("/path/in/src");
InputStream is = getClass().getResourceAsStream("/path/in/src");
If your app is NOT assemble in JAR - try provide full path to file like this:
URL url = getClass().getResource("/path/in/src");
File file = new File(url.toURI());
The files from Classpath can be loaded by using ClassLoader's getResourceAsStream Method.
So you can try with generating an Input stream object
InputStream is = Controller.class.getClassLoader().getResourceAsStream("doc/documentation.pdf");
And After generating Input Stream you can read it by Java Program.

Java Ant: classpath hierachy

I have several class files like such hierarchy directories:
classes
└── com
├── www
│   ├── ant
│   │   └── TAPJUnitResultFormatter.class
│   ├── taglib
│   │   └── IncludeTag.class
│   ├── tomcat
│ ├── util
How could I include them in classpath? I tried to include them one by one, but didn't work.
Thanks.
You might find this helpful
Quoted:
When classes are stored in a directory (folder), like /java/MyClasses/utility/myapp, then the class path
entry points to the directory that contains the first element of the
package name. (in this case, /java/MyClasses, since the package name
is utility.myapp.)
But when classes are stored in an archive file (a .zip or .jar file)
the class path entry is the path to and including the .zip or .jar
file. For example, to use a class library that is in a .jar file, the
command would look something like this:
% java -classpath /java/MyClasses/myclasses.jar utility.myapp.Cool
So basically, point it to the root directory that all your classes exist under. Your "MyClasses" folder is probably named "bin".

Categories