how do you execute .JAR files within java - java

How do you execute a JAR file within your source code?
I know that for an exe, you use
try
{
Runtime rt = Rintime.getRuntime() ;
Process p = rt.exec("Program.exe") ;
InputStream in = p.getInputStream() ;
OutputStream out = p.getOutputStream ();
InputSream err = p,getErrorStram() ;
//do whatever you want
//some more code
p.destroy() ;
}catch(Exception exc){/*handle exception*/}
Is it the same only:
rt.exec("program.exe") changes to rt.jar("program.jar") or is it something different?

In order to extract a jar file instead of exec("program.exe") you need to say
exec("<path to jar command> -xf program.jar")
Usually the jar command is available in your bin directory and if the env variables are properly set , you can even say
exec("jar -xf program.jar")
For running the jar file you can say "java -jar program.jar"

You can use java.util.jar.JarFile API to read the content of jar file.
Following is the code sample of how to use it to extract a file from a jar file:
File jar = new File("Your_Jar_File_Path")
final JarFile jarFile = new JarFile(jar);
for (final Enumeration<JarEntry> files = jarFile.entries(); files.hasMoreElements();)
{
final JarEntry file = files.nextElement();
final String fileName = file.getName();
final InputStream inputStream = jarFile.getInputStream(file);
........
while (inputStream.available() > 0)
{
yourFileOutputStream.write(inputStream.read());
}
}

Related

Random file from a folder inside JAR

I want to get a random image from a specific folder in Java. The code does already work inside the Eclipse IDE, but not in my runnable JAR. Since images inside the JAR file are not files, the code below results in a NullPointerException, but I'm not sure how to "translate" the code so that it will work in a runnable JAR.
final File dir = new File("images/");
File[] files = dir.listFiles();
Random rand = new Random();
File file = files[rand.nextInt(files.length)];
If the given path is invalid then listFiles() method reutrns null value. So you have to handle it if the path is invalid. Check below code:
final File dir = new File("images/");
File[] files = dir.listFiles();
Random rand = new Random();
File file = null;
if (files != null) {
file = files[rand.nextInt(files.length)];
}
If the jar is to contain the images then (assuming a maven or gradle project) they should be in the resources directory (or a subdirectory thereof). These images are then indeed no 'Files' but 'Resources' and should be loaded using getClass().getResource(String name) or getClass.getResourceAsStream(String name).
You could create a text file listing the resource paths of the images. This would allow you to simply read all lines from that file and access the resource via Class.getResource.
You could even create such a list automatically. The following works for my project type in eclipse; some minor adjustments may be needed for your IDE.
private static void writeResourceCatalog(Path resourcePath, Path targetFile) throws IOException {
URI uri = resourcePath.toUri();
try (BufferedWriter writer = Files.newBufferedWriter(targetFile, StandardCharsets.UTF_8)) {
Files.list(resourcePath.resolve("images")).filter(Files::isRegularFile).forEach(p -> {
try {
writer.append('/').append(uri.relativize(p.toUri()).toString()).append('\n');
} catch (IOException e) {
throw new RuntimeException(e);
}
});
}
}
writeResourceCatalog(Paths.get("src", "main", "resources"), Paths.get("src", "main", "resources", "catalog.txt"));
After building the jar with the new file included you could simply list all the files as
List<URL> urls = new ArrayList<>();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(WriteTest.class.getResourceAsStream("/catalog.txt"), StandardCharsets.UTF_8))) {
String s;
while ((s = reader.readLine()) != null) {
urls.add(SomeType.class.getResource(s));
}
}
It seem like a path Problem, maybe will work if tried absolute path for image directory or set maon directory for java configuration

Java creating a test file from a jar

I want to have a java app, where after starting the jar I get a file for example a test.txt within the same folder as the jar.
For example I click on the jar and in the same folder I get a test.txt file.
The below code works in eclipse and creates the file, but after an export to jar, no file is produced.
Would be very happy if you could help.
public class FileWriterTest {
public static void main(String[] args) {
String fileName = "test.txt";
try(
FileWriter fileWriter = new FileWriter(fileName);
BufferedWriter writer = new BufferedWriter(fileWriter);
) {
writer.write("Hello");
} catch(IOException e) {
e.printStackTrace();
}
}
}
With System.getProperty("user.dir") you can get the current "working directory".
If you want to create a file in that specific directory you could use the following code:
String workingDirectory = System.getProperty("user.dir");
File file = new File(working directory + File.separator + "filename.txt");
file.createNewFile();
If you are running as java -jar yourjar.jar, it will not take the additional classpath.
You need to add your jar and location where file resided in classpath and call java command for Main class
example
Linux
java -classpath .:path_dir_with_jar/*:path_to_file MainClass
Windows
java -classpath .;path_dir_with_jar/*;path_to_file MainClas
Finally can read as
InputStream in = this.getClass().getClassLoader()
.getResourceAsStream("SomeTextFile.txt")
;

No Such File exception in Runnable Jar file

I am trying to create a runnable jar file. My project includes models.txt file. My project works perfectly in eclipse with no error but when exported to a runnable jar file, It doesn't work. I hereby attach the error and the piece of code where the file is been called.
public static HashMap<String, RenderModel> getModelList(String file) throws IOException {
List<String> data;
HashMap<String, RenderModel> namesToModels = new HashMap<String, RenderModel>();
if (file != null) {
data = Files.readAllLines(Paths.get(file), StandardCharsets.UTF_8);
} else {
String path = "models/models.txt";
data = Files.readAllLines(Paths.get(path), StandardCharsets.UTF_8);
}
Iterator<String> dataIterator = data.iterator();
while (dataIterator.hasNext()) {
String dataLine = dataIterator.next();
System.out.println(dataLine);
String[] line = dataLine.split("; ");
String key = line[0];
String valueObj = line[1];
String valueMtl = line[2];
float scale = Float.parseFloat((String) line[3]);
RenderModel v = new RenderModel(valueObj, valueMtl, scale);
namesToModels.put(key, v);
}
RenderModel v = new RenderModel("custom", "custom", 1.0f);
namesToModels.put("Choose Model from file", v);
return namesToModels;
}
Error Image:
If the files are in the Jar and you cannot read them, try accessing the files by doing:
getClass().getClassLoader().getResource(fileName);
Use this instead for static methods:
ClassName.class.getClassLoader().getResource(fileName);
Where fileName is the name of the file and ClassName the name of the class from which the statement is called.
In your code the path of the model.txt is 'src/models/model.txt'. When your project is packaged the src folder is not included usually. Then you must change the file location; could be better put the file outside the jar, but inside the java classpath.
It does not work because you do not have any file on the path src/models/models.txt when you run your jar else where, this path is only present in your IDE (ofcourse you can place your jar in a location from where it can reach that path, but this is not how it is supposed to be), when you package your project into a jar file it is packed in the package models and you can if you want to have it as default file read it via classpath.

How can I load a .class file from a running jar into a Java Object in order to read the annotations inside the class file?

I have packaged a maven project using the maven assembly plugin in order to get a single jar file.
I packaged the following java classes from the folder src/test/java (TestNG tests) into a jar file.
The following classes are in the following path inside the jar:
target/test-classes/com/example/tests/ByCitiesTest.class
target/test-classes/com/example/tests/FullCycle3HoursTest.class
I can read the location of these classes running the jar but I want to load these classes in order to read the TestNG annotations (e.g: #Test, #DataProvider,...) and run them using a custom TestRunner I have developed.
I used the following code to read inside the jar and trying to load the .class file:
List<XmlClass> classes = new ArrayList<XmlClass>();
Path currentRelativePath = Paths.get("");
String s = currentRelativePath.toAbsolutePath().toString();
System.out.println("Current relative path is: " + s);
CodeSource src = TestRunner.class.getProtectionDomain().getCodeSource();
URL jar = src.getLocation();
JarFile jarFile = new JarFile(jar.getPath());
Enumeration e = jarFile.entries();
if (src != null) {
ZipInputStream zip = new ZipInputStream(jar.openStream());
ZipEntry ze;
while ((ze = zip.getNextEntry()) != null) {
String entryName = ze.getName();
if (entryName.contains("target") && entryName.contains(".class") && entryName.contains("test")) {
System.out.println(entryName);
}
}
}
URL[] urls = {new URL("jar:file:" + jar.getPath() + "!/")};
URLClassLoader cl = URLClassLoader.newInstance(urls);
InputStream in = cl.getResourceAsStream("target/test-classes/com/example/tests/ByCitiesTest.class");
byte[] array = new byte[1024];
ByteArrayOutputStream out = new ByteArrayOutputStream(array.length);
int length = in.read(array);
while (length > 0) {
out.write(array, 0, length);
length = in.read(array);
}
Class testclass = classHandler.defineCustomClass("ByCitiesTest", out);
XmlClass singleClass = new XmlClass(testclass.getName());
classes.add(singleClass);
And the function defineCustomClass
public Class defineCustomClass(String name, ByteArrayOutputStream out) {
return defineClass(name, out.toByteArray(), 0, out.size());
}
This function uses defineClass from the Java ClassLoader class.
And the error I get on execution is as follows:
Current relative path is: /Users/root/path/of/the/project-webdriver
target/test-classes/com/example/BaseByHoursTest.class
target/test-classes/com/example/pages/CardInformationPage.class
target/test-classes/com/example/pages/ConfirmationPage.class
target/test-classes/com/example/pages/ContactPage.class
target/test-classes/com/example/pages/ExtrasPage.class
target/test-classes/com/example/pages/HomePage.class
target/test-classes/com/example/pages/HotelPage.class
target/test-classes/com/example/pages/ResultsPage.class
target/test-classes/com/example/tests/ByCitiesTest.class
target/test-classes/com/example/tests/FullCycle3HoursTest.class
Exception in thread "main" java.lang.NoClassDefFoundError: ByCitiesTest (wrong name: com/example/tests/ByCitiesTest)
I don't know which is the name of the class and how I can know that name. I tried to load the file into an InputStream and then try it to load it using a ClassLoader.
How can I load the file .class into java Class object?
How can I read the annotations from these classes which are inside a jar file?

How to Declare Folder Path?

I have a desktop application using Swing library. Application is running a batch file. So I created a lib folder in main project directory and put batch file in it. To run this, I am showing lib\a.exe to run this. It is working on my laptop. I exported .jar and put lib folder next to it. It is working on my laptop, but not working on some other laptops. How to fix this?
Error message is: Windows cannot found lib\a.exe.
String command = "cmd /c start lib\\a.exe";
try {
Runtime.getRuntime().exec(command);
increaseProgressBarValue();
} catch (IOException e) {
e.printStackTrace();
}
You need two things:
find the directory of the jar file of your application
call a.exe with the correct working directory
You can get the location of the jar with the getJar method below:
private static File getJar(Class clazz) throws MalformedURLException {
String name = clazz.getName().replace('.','/') + ".class";
ClassLoader cl = Thread.currentThread().getContextClassLoader();
URL url = cl.getResource(name);
System.out.println(url);
if (!"jar".equals(url.getProtocol())) {
throw new MalformedURLException("Expected a jar: URL " + url);
}
String file = url.getPath();
int pos = file.lastIndexOf('!');
if (pos < 0) {
throw new MalformedURLException("Expected ! " + file);
}
url = new URL(file.substring(0, pos));
if (!"file".equals(url.getProtocol())) {
throw new MalformedURLException("Expected a file: URL " + url);
}
String path = url.getPath();
if (path.matches("/[A-Za-z]:/")) { // Windoze drive letter
path = path.substring(1);
}
return new File(path);
}
To call lib\a.exe, you can do something like this:
File jar = getJar(MyClass.class); // MyClass can be any class in you jar file
File dir = jar.getParentFile();
ProcessBuilder builder = new ProcessBuilder();
builder.command("lib\\a.exe");
builder.directory(dir);
...
Process p = builder.start();
...
Maybe you have to try if this folder lib exists and if it doesn't than create it with
file.mkdir();
This is a just a checking. But your filepath must be like this ../lib/a.exe.

Categories