Adding a External Folder to the ClassPath in a runnable jar - java

I have a maven project where I create a jar with dependencies using maven assembly plugin. I also have an external config file ( conf.properties ) that is required by the jar to work properly.
My project structure is like this:
|- abc.jar
|- config
|-conf.properties
How can I add this config folder to the classpath of the jar file? I tried to do this using -cp command and manipulating class-path property in MANIFEST.MF file but no luck so far.
Does anyone know a way to do this?

This is how I tested (sorry, no maven)!
Main class:
package cfh.sf.Chamika;
import java.util.ResourceBundle;
public class ABC {
public static void main(String[] args) {
var bundle = ResourceBundle.getBundle("conf");
System.out.println(bundle.getString("test"));
}
}
Manifest file, note empty line at end (entries must end with a newline (CR, LF or CRLF)):
Manifest-Version: 1.0
Main-Class: cfh.sf.Chamika.ABC
Class-Path: config/
Directory structure
dist/
abc.jar
config/
conf.properties
Content of conf.properties:
test = OK, it is working!
Executed with
java -jar abc.jar
Alternative, not using ResourceBundle:
package cfh.sf.Chamika;
import java.io.IOException;
public class ABC {
public static void main(String[] args) {
try (var input = ClassLoader.getSystemResourceAsStream("conf.properties")) {
int ch;
while ((ch = input.read()) != -1) {
System.out.print((char) ch);
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}

Related

Jar file and resource file returning null

I have a simple program that reads a text file (test.txt) line by line and prints each line to the console. In intellij it works just fine.
import java.io.FileNotFoundException;
import java.util.Scanner;
import java.io.File;
public class testing {
public static void main(String[] args) {
testing main= new testing();
main.handleData("test.txt");
// handleData();
//System.out.println("hello world");
}
public void handleData(String fileName) {
System.out.println("Testing");
File file= new File(getClass().getResource(fileName).getPath());
try {
Scanner scanner = new Scanner(file);
while(scanner.hasNextLine()){
System.out.println(scanner.nextLine());
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
I am trying to build it with gradle and when i run the jar command java -jar out/artifacts/helloTestingWorld_jar/helloTestingWorld.jar I get an error saying the path is null
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.net.URL.getPath()" because the return value of "java.lang.Class.getResource(String)" is null
at testing.handleData(testing.java:22)
at testing.main(testing.java:12)
My build.gradle file looks like this
plugins {
id 'java'
}
group 'org.example'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
}
jar {
manifest {
attributes "Main-Class": "src.main.java.testing"
}
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
}
test {
useJUnitPlatform()
}
My resource folder is marked as the resource root and my java folder that contains my main class is marked as the source root. I am thinking that I might have to add the text file as a dependency in the jar file?
I have had a look at all of the other suggestions on here and the all lead to the same result. I have tried rebuilding the project from scratch and still the same result.
I have also tried using InputStream instead of File
InputStream in = getClass().getResourceAsStream(fileName);
When I use InputStream I get this error
Exception in thread "main" java.lang.NullPointerException
at java.base/java.io.Reader.<init>(Reader.java:168)
at java.base/java.io.InputStreamReader.<init>(InputStreamReader.java:76)
at java.base/java.util.Scanner.<init>(Scanner.java:566)
at testing.handleData(test.java:23)
at testing.main(test.java:10)

How to check if file exist after build jlink?

I am trying to check if file exists in project. When I start my application through Intellij idea and check if file exists it's return true but when I create jlink build and start it through .bat and check if file exists it's always return false.
public class App {
public static String getPathToDllTest(String filename) throws URISyntaxException {
return Paths.get(App.class.getResource("files/" + filename + ".txt").toURI()).toString();
}
public static void main(String[] args) throws Exception {
File txt = new File(App.getPathToDllTest("test"));
System.out.println(txt.exists());
}
}
Here is basic Maven project resources structure I use:
src
main
java
com
example
App.java
resources
com
example
files
test.txt
Is there problem in path? How can I fix it?

Deploy java spring-boot app *.jar to heroku with other files in root folder

I have a spring boot app as qsysprereg2-1.0.jar. I pushed into heroku git already compiled jar file + Procfile + folder "config" with files for my app as "config/config.properties". Just some properties.
In Gradle I have only:
apply plugin: 'java'
task stage() {
println("Go stage...")
}
All compiled and deployed successfully.
In result I have error:
java.io.FileNotFoundException: config/config.properties (No such file or directory)
Of course, because:
Running bash on ⬢ qprereg... up, run.9546 (Free)
~ $ ls
Procfile qsysprereg2-1.0.jar system.properties
Where is no folder "config" from git. But "config/config.properties" had been pushed into git.
How to add the folder with files to deploy artifacts?
Sorry, but I did not find a nice solution. I made some tricks. I put all my config files in jar as resources. During starting the app I am checking the files outside jar on dick then coping from resources to dist. New files are keeping on disk without problems. Code for that:
public static void main(String[] args) {
try {
prepareConfig();
} catch (IOException ex) {
log.error("Config prepare fail.", ex);
log.throwing(ex);
throw new RuntimeException(ex);
}
SpringApplication.run(Application.class, args);
}
private static void prepareConfig() throws IOException {
File dir = new File("config");
if (!dir.exists() || !dir.isDirectory()) {
log.info("Create config directory");
Files.createDirectory(dir.toPath());
}
makeReady("config/config1.properties");
makeReady("config/config2.properties");
makeReady("config/config3.properties");
makeReady("config/configN.properties");
}
private static void makeReady(String fileName) throws IOException {
File file = new File(fileName);
if (!file.exists()) {
log.info("Create config file '{}'", file.getName());
try (final InputStream stream = Application.class.getResourceAsStream("/" + fileName)) {
Files.copy(stream, file.toPath());
}
}
}

How to get path to class file in eclipse and linux in java?

In eclipse for windows, when I run
public class HelloWorld {
public static void main(String[] args) {
System.out.println(System.getProperty("user.dir"));
}
}
It gives me the path of the project root folder (which contains the bin folder which has the class file). For example
SampleProject
and the class file is actually located at
SampleProject\bin\myclass.class
But if I run the same program in linux with
javac myclass.java
java myclass
it gives me the directory that has the .class file, which is the same as pwd command. This is what I want in eclipse for windows. I want some code that will give me the path to the class file in both eclipse for windows and linux.
Does anyone know how do this?
Thanks
If I understand you correctly, you'd like a method that retrieves a class' path on disk. This is easily achievable, like so:
public String getClassPath(Class c) {
try {
return c.getProtectionDomain().getCodeSource().getLocation().toURI().getPath();
} catch (URISyntaxException e) {
e.printStackTrace();
}
return null;
}
NOTE this will work even if the class is contained in a jar file. It will return the path to the jar in this case.
The easiest way is to do this:
public class HelloWorld {
public static void main(String[] args) {
System.out.println(HelloWorld.class.getResource("HelloWorld.class"));
}
}

Listing classes in a jar file

How can I dynamically load a jar file and list classes which is in it?
Here is code for listing classes in jar:
import java.io.IOException;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class JarList {
public static void main(String args[]) throws IOException {
if (args.length > 0) {
JarFile jarFile = new JarFile(args[0]);
Enumeration allEntries = jarFile.entries();
while (allEntries.hasMoreElements()) {
JarEntry entry = (JarEntry) allEntries.nextElement();
String name = entry.getName();
System.out.println(name);
}
}
}
}
You can view the contents of a JAR file from command prompt by using the following command:
jar tf jar-file
For example:
jar tf TicTacToe.jar
META-INF/MANIFEST.MF
TicTacToe.class
audio/
audio/beep.au
audio/ding.au
audio/return.au
audio/yahoo1.au
audio/yahoo2.au
images/
images/cross.gif
images/not.gif
Have a look at the classes in the package java.util.jar. You can find examples of how to list the files inside the JAR on the web, here's an example. (Also note the links at the bottom of that page, there are many more examples that show you how to work with JAR files).
Fast way: just open the .jar as .zip e.g. in 7-Zip and look for the directory-names.
Here is a version that scans a given jar for all non-abstract classes extending a particular class:
try (JarFile jf = new JarFile("/path/to/file.jar")) {
for (Enumeration<JarEntry> en = jf.entries(); en.hasMoreElements(); ) {
JarEntry e = en.nextElement();
String name = e.getName();
// Check for package or sub-package (you can change the test for *exact* package here)
if (name.startsWith("my/specific/package/") && name.endsWith(".class")) {
// Strip out ".class" and reformat path to package name
String javaName = name.substring(0, name.lastIndexOf('.')).replace('/', '.');
System.out.print("Checking "+javaName+" ... ");
Class<?> cls;
try {
cls = Class.forName(javaName);
} catch (ClassNotFoundException ex) { // E.g. internal classes, ...
continue;
}
if ((cls.getModifiers() & Modifier.ABSTRACT) != 0) { // Only instanciable classes
System.out.println("(abstract)");
continue;
}
if (!TheSuper.class.isAssignableFrom(cls)) { // Only subclasses of "TheSuper" class
System.out.println("(not TheSuper)");
continue;
}
// Found!
System.out.println("OK");
}
}
} catch (IOException e) {
e.printStackTrace();
}
You can use that code directly when you know where are your jars. To get that information, refer to this other question, as going through classpath has changed since Java 9 and the introduction of modules.

Categories

Resources