Open a file from the src directory (Java) - 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.

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.

NiFi-1.0.0 - load lua script

I have a NiFi processor, that uses the redislabs/luascript lib in order to load a lua script and execute it on a redis instance.
The thing is that I don't know where exactly to put the lua script in order to load it using the luascript lib. I've put it into the nifi_proc/src/main/resources/lua/name.lua, but I get an IOException.
I have a nifi controller service for connecting to redis and a processor that uses that service.
My project structure:
.
├── nifi-bundle-nar
│   └── target
├── nifi-redis_cservice
│   ├── src
│   └── target
├── nifi-redis_cservice-api
│   ├── src
│   └── target
├── nifi-redis_cservice-api-nar
│   └── target
├── nifi-redis_cservice-nar
│   └── target
├── redis-processors
│   ├── src
│   └── target
└── target
└── maven-shared-archive-resources
Any ideas?
Can you share more information about how the processor is interacting with the library? Are you passing in an InputStream, calling out to a executable, etc.?
Ensure your resource is in the JAR module of your processor's project, not the processor's NAR module or the parent (that includes both). You should be able to use getResourceAsStream("lua/name.lua") from a Class object that is in the processor's JAR file (such as the processor class itself). I'm not sure what you'd need to do with it after that, is it possible to share the source code or more details around it?
EDIT (reply to comments below): fromResource() uses LuaScript's classloader to get the resource, I wonder if it doesn't have access to the nifi-proc or controller service resources. It seems like, unless the user needs to specify the location of the script, that the controller service should be loading in the Lua script. So an alternative could be to use the controller service class to getResourceAsStream, read the whole thing into a String, and use fromSource instead of fromResource.

Java jar can't access resources

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.

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".

Why Can't I access src/test/resources in Junit test run with Maven?

I am having a problems running the following code:
configService.setMainConfig("src/test/resources/MainConfig.xml");
From within a Junit #Before method.
Is this the way Maven builds out its target folder?
Access MainConfig.xml directly. The src/test/resources directory contents are placed in the root of your CLASSPATH.
More precisely: contents of src/test/resources are copied into target/test-classes, so if you have the following project structure:
.
└── src
└── test
├── java
│   └── foo
│   └── C.java
└── resources
├── a.xml
└── foo
└── b.xml
It will result with the following test CLASSPATH contents:
/foo/C.class
/a.xml
/foo/b.xml
To actually access the files from Java source, use
getClass().getResource("/MainConfig.xml").getFile().
I ran into the same problem today and I have found some solutions.
First, here is my file structure:
.
└── src
│ └── test
│ ├── java
│ │ └── mypackage
│ │ └── MyClassTest.java
│ └── resources
│ └── image.jpg
└── target
└── test-classes
├── image.jpg
└── mypackage
└── MyClassTest.class
What is not working: (Java 11 synthax)
var imgFile = new File("image.jpg"); // I was expecting that Junit could find the file.
var absPath = file.getAbsolutePath(); // /home/<user>/../<project-root>/image.jpg
var anyFileUnderThisPath = file.exists(); // false
What we can notice is that the absolute path does not point at all on my image! But if I had an image under at the project-root, then it would have worked.
Solution 1: Paths (introduced in Java 7)
var relPath = Paths.get("src", "test", "resources", "image.jpg"); // src/test/resources/image.jgp
var absPath = relPath.toFile().getAbsolutePath(); // /home/<user>/../<project-root>/src/test/resources/image.jpg
var anyFileUnderThisPath = new File(absPath).exists(); // true
As we can see, it points on the right file.
Solution 2: ClassLoader
var classLoader = getClass().getClassLoader();
var url = classLoader.getResource("image.jpg"); // file:/home/<user>/../<project-root>/target/test-classes/image.jpg
var file = new File(url.getFile()); // /home/<user>/../<project-root>/target/test-classes/image.jpg
var anyFileUnderThisPath = file.exists(); // true
Note that now the file is searched under the target directory! and it works.
Solution 3: File (Adaptation of the non-working example)
var absPath = new File("src/test/resources/image.jpg").getAbsolutePath();
var var anyFileUnderThisPath = new File(absPath).exists(); // true
Which works also after taking the absolute path and putting src/test/resources/ as prefix.
Summary
All three solutions works but having to put src/test/resources/ is, in my own opinion not elegant, and this is why I would prefer the 2nd solution (ClassLoader).
Sources:
Read file and resource in junit test
Java read a file from resources folder
I guess setMainConfig expects the path of a resource, that it will load using the ClassLoader, and not a relative file path. It would help if you linked to the javadoc of this mysterious configService.setMainConfig method.
If my guess is correct, then the path should just be MainConfig.xml. Mave copies the contents of src/test/resources to the target/test-classes (IIRC) folder. And this test-classes folder is in the classpath of the unit tests.

Categories