Reading resource from jar isn't working as expected - java

I'm attempting to create an executable jar for a selenium test. Part of the things the code needs to do is set a system property to tell Selenium where the driver executable can be found (I'm using the chromedriver). File structure is as follows:
src
com
mycompany
SeleniumTest.java
chromeDriver
windows
chromedriver.exe
And the code is as follows:
private static String WINDOWS_DRIVER = "/chromeDriver/windows/chromedriver.exe";
System.setProperty("webdriver.chrome.driver",
SeleniumTest.class.getResource(WINDOWS_DRIVER).getFile());
When executed in eclipse, this code works fine. However, when I export to a runnable jar file (from eclipse) I get the following error:
Exception in thread "main" java.lang.IllegalStateException: The driver executable
does not exist: F:\temp\file:\F:\temp\seleniumTest.jar!\chromeDriver\windows\chromedriver.exe
at com.google.common.base.Preconditions.checkState(Preconditions.java:177)
at org.openqa.selenium.remote.service.DriverService.checkExecutable(DriverService.java:117)
at org.openqa.selenium.remote.service.DriverService.findExecutable(DriverService.java:112)
at org.openqa.selenium.chrome.ChromeDriverService.createDefaultService(ChromeDriverService.java:75)
at org.openqa.selenium.chrome.ChromeDriver.<init>(ChromeDriver.java:139)
And yet seleniumTest.jar exists at F:\temp as does the path within the jar which the error message specifies.
Any ideas on what is wrong or suggestions to try? I've tried changing the slahses to backslashes and also (just as a test) hard coding the path (e.g. setting the system property to F:\temp\seleniumTest.jar!\chromeDriver\windows\chromedriver.exe), but neither has worked.

The system property is supposed to contain the path to the file, on the file system, where the driver can be found and executed.
The driver is not a file. It's an entry of your jar file. Executables bundled in a jar file can't be executed.
If you really want to bundle the driver into your jar file and execute it, then you'll have to read the bytes from this classpath resource, write them to a temporary executable file, and then tell selenium where this temporary executable file is located.

Try something like:
// locate chromedriver in the jar resources
URL res = getClass().getResource("/chromeDriver/windows/chromedriver.exe");
// locate chromedriver in the jar filesystem
File f = new File(res.getFile());
// copy chromedriver out into the real filesystem
File target = new File(System.getProperty("java.io.tmpdir") + System.getProperty("file.separator") + f.getName());
java.nio.file.Files.copy(f.toPath(), target.toPath(), StandardCopyOption.REPLACE_EXISTING);
if (!target.canExecute())
throw new FileNotFoundException("chrome.exe copy did not work!");
System.setProperty("webdriver.chrome.driver", target.getCanonicalPath());

Related

Cannot run program file:/runtime.jar!/some_binary: error=2, No such file or directory (Kotlin)

i am working on a kotlin project and in my task i have to execute binary from code using ProcessBuilder.
i copied this binary to resources, tested my code and everything worked good locally.
val url = ConversionTool::class.java.classLoader.getResource("my_binary_file_name")
url!! //ensure that file exists, just for test
val process = ProcessBuilder(url.path).start()
But when i deploy this code to docker testing environment, i get following exception:
java.io.IOException: Cannot run program "file:/runtime.jar!/my_binary_file_name": error=2, No such file or directory
at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1128)
at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1071)
Why is this happening? I made sure that my_binary_file_name exists in runtime.jar in container and url variable is not null.
The "file" is inside the ziĆ¼ file runtime.jar. Its URL is jar:file:/.... So first the jar: protocol. In Java File is a file on the disk, and the generalization Path can also be a file inside a zip or an URL, or some custom file system like for LDAP or whatever.
However with Process from the ProcessBuilder you are again one the operating system level. There is no jar: URL handler, just file:, html:, mailto: and such.
However you can copy the Path from the URL to a temporary file, and execute that, using Files#createTempFile.
Path path = Paths.get(url.toURI());
Path file = Files.createTempFile'(...);
Files.copy(path, file);
Windows has the feature of zip folders, so you might try to name the jar as .zip (and use "file: ... runtime.zip/ ...". But I have no experience with that.

How to refer to a file inside spring boot application jar as a -D property value while starting the app from command line?

I have a simple spring boot application that needs java.security.krb5.conf property value set to a custom krb5.conf file. I have added the file inside the src/main/resources folder and maven make it packaged into the jar.
to start the app , I run
java -jar -Djava.security.krb5.conf=<localPath>/krb5.conf my-jar.jar
currently I have to give the <localPath> as the path to the file on my machine. Is there a way to refer to the file inside the jar so that I can run in any machine without creating the file file first on the machine?
things I tried so far:
give -Djava.security.krb5.conf=classpath:krb5.conf (also ./krb5.conf). Didn't work
I see most of the examples for 'how to read files from class path' refer to getClass.getResource (filename). So I tried do getClass.getResource (filename).getPath() so that I can set it as java.security.krb5.conf system property while starting the app in main class instead of passing from command line. But the string that getPath shows is something like /<diskPath>/my-jar.jar!/BOOT-INF/classes!/krb5.conf and this path is not working when I try to read the file for testing.
Create a copy of the file to the running dir on-the-fly, in main method before calling SprinApplication.run. This is what I am doing now.
try(
InputStream in = new ClassPathResource("krb5.conf").getInputStream();
OutputStream out = new FileOutputStream( new File("krb5copy.conf"));) {
IOUtils.copy(in, out);
}
System.setProperty("java.security.krb5.conf","krb5copy.conf");
If there is a solution for this question , I can see other use cases such as providing the trustore file included in jar as javax.net.ssl.trustStore etc.
give -Djava.security.krb5.conf=classpth:krb5.conf (also ./krb5.conf).
Didn't work
It's not 'classpth' it's 'classpath', actually. AND with a slash after it.
-Djava.security.krb5.conf=classpath/:krb5.conf should work.
The code that reads the krb5.conf configuration file uses FileInputStream, which requires the path to the file and doesn't "understand" classpath: prefix.
The idea below is to locate the file on the classpath and from that to get the path to the file:
ClassPathResource resource = new ClassPathResource("krb5.conf");
try
{
String fileSpec = resource.getURL().getFile();
System.setProperty("java.security.krb5.conf", fileSpec);
}
catch (IOException e)
{
// TODO handle the exception
e.printStackTrace();
}
EDIT: When packaged as SpringBoot fat JAR, trying to read the file with FileInputStream results in java.io.FileNotFoundException: file:/<path-to-jar/<jar-name>.jar!/BOOT-INF/classes!/krb5.conf (No such file or directory) :-(

How to find the path of a file local eclipse project

I have created a .txt file in my Eclipse Java project, and I want to find out the path to it so I can use it for a Scanner. I do not want to find out the path on my local drive, as I will be planning to share the program to someone else, and they will have a different folder structure, rather a path that can be used on anybodies machine.
Here is the code:
this.file = new File("<insert path here>");
you can use :
= new File("Build Path"); (your .java file exist in your build path)
The build path is used for building your application. It contains all of your source files and all Java libraries that are required to compile the application.
In eclipse, the default behavior is for the Java system property user.dir to be set to the project directory. This is what dictates where the "root" of File operations is. So if you created a file test.txt in the root project directory, you should be able to access it with new File("test.txt").
However, as Andrew Thompson mentioned in his comment, the more correct method would be using embedded resources.
Try one of These:
1.
System.getProperty("user.dir");
2.
File currentDirFile = new File(".");
String helper = currentDirFile.getAbsolutePath();
String currentDir = helper.substring(0, helper.length() - currentDirFile.getCanonicalPath().length());//this line may need a try-catch
I have not tested it just found while googling

Get path from inside a JAR File (for system property in selenium)

I am using Selenium Webdriver in Java for creating accounts from a excel file for a mediawiki software. I am working with eclipse.
When i try to export my project to a runnable jar file, there are some problems.
I have a file named "geckodriver.exe" im my resources folder (projectname/src/resources/geckodriver.exe)
All i want to do is to set a system property for selenium, so the user not have to manually choose the gecko driver file for working correctly with selenium.
This is my actual code, working inside eclipse
String filename = "geckodriver.exe";
File geckodriverFile = new File(this.getClass().getProtectionDomain().getCodeSource().getLocation().getPath());
geckodriverPath = geckodriverFile.getAbsolutePath() + "\\resources\\" + filename;
And finally i want to set the system property
System.setProperty("webdriver.gecko.driver", geckodriverPath);
How can i achieve this to work inside a jar file?

Uncompiled jar works but compiled doesn't work

So in Eclipse this code works:
String file_path = "accounts.accs";
File file = new File("src/puffinlump/folder_lock/"+file_path);
But when I compile it into a JAR I get this error:
Error reading file: java.io.FileNotFoundException: lock\src\puffinlump\folder_lock\accounts.accs (The system cannot find the path specified)
Why is it not working and how can I fix it?
As Obicere said, the working directory is the project directory. You try to access something in the src folder, which probably doesn't exist wherever you exported your JAR. You should create a folder named folder_lock in your project directory with accounts.accs in it, then get your file with:
File file = new File("folder_lock" + File.separator + "accounts.accs");
If you need it in your JAR (which it's being exported to, given that it's in the src folder) then retrieve an InputStream from it like this:
InputStream stream = getClass().getClassLoader().getResourceAsStream("puffinlump/folder_lock/accounts.accs");
If your method is static, use
InputStream stream = MyClass.class.getClassLoader().getResourceAsStream("puffinlump/folder_lock/accounts.accs");
instead, substituting your class name over MyClass.
If you need an URL, you can retrieve one with getResource instead of getResourceAsStream.
Note that your code must be compiled to run - Eclipse compiles it by default every time you save.

Categories

Resources