Executable Jar : Issue in accessing pom while executing jar - java

I am trying to create an executable jar for my Maven-TestNG project. My ultimate target is to execute code in any machine just by jar files. My plan is to put all required/dependency jar files in a folder and pass the folder as -classpath.
As an executable jar needs a Main class, I created a main class and performing the goals by using InvocationRequest . As part of my goal, my TestNG.xml will be executed.
InvocationRequest request = new DefaultInvocationRequest();
File file = new File("pom.xml");
File fileWithPath = new File(file.getAbsolutePath());
request.setPomFile(new File(fileWithPath));
request.setGoals(Collections.singletonList("clean verify"));
DefaultInvoker invoker = new DefaultInvoker();
invoker.setMavenHome(new File(System.getenv("M2_HOME")));
try {
invoker.execute(request);
} catch (MavenInvocationException e) {
e.printStackTrace();
}
Above code is working fine when I execute it from Eclipse.
But once I do packaging and try to execute Java -cp lib/* com.test.package.runner.InvokerClass from C:\TestProject by using , it is showing as C:\TestProject\lib\pom.xml is not found. I understood that pom.xml wont present on jar level, Instead it will be under C:\TestProject\lib\TestProject.jar!\META-INF\maven\com.test.package\TestProject\pom.xml.
So how can I get the path of pom.xml from META-INF folder during run-time?
I tried setting pom.xml path in different ways as follows. But nothing worked well. Any suggestions please?
Most of the time, I got nullpointer exception as it couldn't find the path.
URL path = InvokerClass.class.getClass().getClassLoader().getResource("pom.xml");
URL path = InvokerClass.class.getClass().getClassLoader().getResource("./pom.xml");
URL path = InvokerClass.class.getClass().getClassLoader().getResource("META-INF/maven/com.adp.aca.test/aca-test-regression/pom.xml");
URL path = InvokerClass.class.getClass().getClassLoader().getResource("./META-INF/maven/com.adp.aca.test/aca-test-regression/pom.xml");

You can prepare the path using the .. in the path.
It will give you the parent directory location from where you are at.
Updated
Suppose you folder structure is as
C:/my-proj/java/Main.java
C:/my-proj/META-INF/pom.xml
Then if you want to find the pom.xml. You can do something like below
String str = System.getProperty("user.dir");
System.out.println(str+"/../META-INF/pom.xml");
Try this.

Related

How to load a JAR stored inside your application resources in a URLClassLoader

I'm trying to load a JAR file in a URLClassLoader. This JAR file is stored in the resources of my project, and its working fine with the following code when I'm running my project using maven:
new URLClassLoader(
new URL[]{MyClass.class.getClassLoader().getResource("dependencies/dependency.jar")},
ClassLoader.getSystemClassLoader().getParent()
);
However, when I build the project using mvn clean install and I then try to run the generate JAR using java -jar myapp.jar it seems like the dependency.jar is not loaded. The dependency.jar file is properly stored inside the project JAR under dependencies/dependency.jar, but it's not read.
I assume that it cannot be loaded from inside a JAR file, but is their a workaround?
I think a solution would be to use getResourceAsStream, but I would then need to transform this stream into a URL.
If possible I'd like to use a solution that wouldn't involve a temporary file created to store the content of dependency.jar.
I believe that your problem is due to the fact that it cannot read a zip in zip, so you should copy your jar file into a temporary file and provide this temporary file to your URLClassLoader as next:
// Get the URL of my jar file
URL url = MyClass.class.getResource("/dependencies/dependency.jar");
// Create my temporary file
Path path = Files.createTempFile("dependency", "jar");
// Delete the file on exit
path.toFile().deleteOnExit();
// Copy the content of my jar into the temporary file
try (InputStream is = url.openStream()) {
Files.copy(is, path, StandardCopyOption.REPLACE_EXISTING);
}
// Create my CL with this new URL
URLClassLoader myCL = new URLClassLoader(
new URL[]{path.toUri().toURL()}, ClassLoader.getSystemClassLoader().getParent()
);

Java NIO filesystem

I am trying to create a Java Swing Application in which I will be storing some image files and CSV files in a subdiretory
com/p/d/resources/project/MyProject
In above project there will be other sub-directories in which I will be storing the images and CSV files. How to access above directory in seamless way. That is even if I run this project as a JAR(which I will ultimately do) or on Eclipse it should give me the access to above directory either as java.nio.file.Path OR java.io.File.
I know I can create a filsystem to iterate JAR but the same code doesn't work when I run it as application in Eclipse. Following is the code I am using for JAR file scenario:
String projectLocationPath = ApplicationProperties
.get(PhaserDesktopConstants.PROJECT_LOCATION_PATH);
CodeSource src = MainController.class.getProtectionDomain()
.getCodeSource();
if (src != null) {
URL jar = src.getLocation();
FileSystem fs = FileSystems.newFileSystem(jar.toURI().normalize(), null);
Path projectDirectory = fs.getPath(projectLocationPath);
if (!Files.isDirectory(projectDirectory)) {
return null;
}
}
Where PhaserDesktopConstants.PROJECT_LOCATION_PATH represents path I gave above. I want to run above code in both scenarios with JAR and without JAR.
I get following path
file:/D:/shailesh/technical/work/eclipse_ws/Phaser%20Desktop/bin/
when I run it in Eclipse and calling
FileSystems.newFileSystem(..)
with this gives me exception
java.lang.IllegalArgumentException: Path component should be '/'
Following some posts on SO I tried hardcoding and changing the path from
file:/D:/shailesh/technical/work/eclipse_ws/Phaser%20Desktop/bin/
to
file:///D:/shailesh/technical/work/eclipse_ws/Phaser%20Desktop/bin/
file://D:/shailesh/technical/work/eclipse_ws/Phaser%20Desktop/bin/
file:///shailesh/technical/work/eclipse_ws/Phaser%20Desktop/bin/
file://shailesh/technical/work/eclipse_ws/Phaser%20Desktop/bin/
but none worked.
Just an Update:
when I debug in eclipse my JAR it gives me following path as location of CodeSource:
file:/D:/shailesh/technical/PhaserD.jar
however error is same its not able to create the filesystem. My OS is Windows 7. JDK 7
You can replace the . with ./../ to switch to a parent directory or with any reference path you'd like. p holds the absolute path, and you can remove the toAbsolutePath() to obtain the referencePath.
Path p = FileSystems.getDefault().getPath(".").toAbsolutePath();
System.out.println(p);

How to load property file located inside jar file

How to load property files placed in resource folder of an executable jar file. Here my app itself is a jar and it executes on it own. It need to find this property file (placed within itself under resource folder) at runtime depending on the path mentioned in the code. I have used below two methods but it didn't help me. Point here is, both these options are working fine when i execute in eclipse, but doesn't work when I pack it into an executable jar. It throws NullPointerException. Only problem I see here is that jar is not able to pick the property files with given path. Any help would be appreciated.
Method 1: Using Apache Commons Configuration
URL propFileURL = XYZ.class.getClassLoader().getResource("/config.properties");
Configuration propertyConfiguration = null;
propertyConfiguration = new PropertiesConfiguration(propFileURL);
In above case I'm getting ConfigurationException. Class is not able to find file mentioned in given path.
Method 2: Using getResourceAsStream. I know that getResource doesn't work if we are to load files from network on in any other location.
InputStream is =XYZ.class.getClassLoader().getResourceAsStream("/config.properties");
Properties prop = new Properties();
prop.load(is);
In this case, I'm getting nullPointerException.
Let me know if you need more details.
jar content Heirarchy
Properties file - /java-file-io-application/src/main/resources/config.properties
XYZ class - /java-file-io-application/src/main/java/org/bc/xyz/iplugin/utilities/XYZ.java
Looks like you might be building your jar incorrectly. Files from 'src/main/resources' would be expected at the root of the jar file. If your jar file contains the 'src/main/resources' directory, something's off with your build.

How to get the path of a directory where my running jar file is?

I try to retrive a path of a directory where my executable jar file is situated.
That means: I have the following structure:
--> Application (this is a folder somewhere in my file system)
--> application.jar (this is my java application
--> SomeData (folder in the same directory like the application)
--> some other folders
......
When I start my application.jar via command line I want to parse some files inside the SomeData folder.
In https://stackoverflow.com/a/320595/1540630 they already showed how to get the current path of a running jar file but when I execute the statement:
System.out.println(XMLParser.class.getProtectionDomain().getCodeSource().getLocation().getPath());
...I just get the following:
/.../Application/application.jar
But I just want to have:
/.../Application/
Better to say in later steps I need
/.../Application/SomeData/SomeFolder/data.xml
Can someone help me please?
CodeSource.getLocation() gives you a URL, you can then create new URLs relative to that:
URL jarLocation = XMLParser.class.getProtectionDomain().getCodeSource().getLocation();
URL dataXML = new URL(jarLocation, "SomeData/SomeFolder/data.xml");
You can't simply do new File(...getCodeSource().getLocation().getPath()) as a URL path is not guaranteed to be a valid native file path on all platforms. You're much safer sticking with URLs and passing the URL directly to your XML parser if you can, but if you really need a java.io.File then you can use an idiom like this to create one from a URL.
Once you have the jar's location you can use
new File(new File(jarPath).getParent(), "SomeData/SomeFolder/data.xml");
Since you already have the path as a string. You can try the following
String path = XMLParser.class.getProtectionDomain().getCodeSource().getLocation().getPath();
String parentFolder = new File(path).getParent();

Access a file from a JAR in the same folder

I need to acces (create and read) a file from a JAR file (executable jar),
and that file should be created in the same directory as the JAR
I tried
this.getClass().getResource("myFile")
but since the jar has packages in it, it won't work..
I also tried write just
File f = new File("myFile");
f.createNewFile();
and that works if i execute the JAR from the terminal, but if i execute the JAR by double-clicking it, the file is created in my home directory -.-''
how do i access a file being SURE that that file is in the SAME directory as the JAR file?
(of course also getting the jar absolute path would do the trick since i can get the parent folder from it)
This will give you the full path to the Jar:
String path = this.getClass().getProtectionDomain().getCodeSource().getLocation().getPath();
EDIT: sorry, was in javascript mode when I wrote that :). As was so politely requested, in a static method you should be able to do this:
String path = Me.class.getProtectionDomain().getCodeSource().getLocation().getPath();
(where the class name is Me).

Categories