Fetch file from specific directory where jar file is placed - java

I want to fetch a text file from the directory where my jar file is placed.
Assuming my desktop application 'foo.jar' file is placed in d:\ in an installation of Windows.
There is also a test.txt file in the same directory which I want to read when 'foo.jar' application is running.
How can fetch that particular path in my 'foo.jar' application?
In short I want to fetch the path of my 'foo.jar' file where it is placed.

Note, that actual code does depend on actual class location within your package, but in general it could look like:
URL root = package.Main.class.getProtectionDomain().getCodeSource().getLocation();
String path = (new File(root.toURI())).getParentFile().getPath();
...
// handle file.txt in path

Most JARs are loaded using a URLClassLoader that remembers the codesource from where the JAR has been loaded. You may use this knowledge to obtain the location of the directory from where the JAR has been loaded by the JVM. You can also use the ProtectionDomain class to get the CodeSource (as shown in the other answer; admittedly, that might be better).
The location returned is often of the file: protocol type, so you'll have to remove this protocol identifier to get the actual location. Following is a short snippet that performs this activity; you might want to build in more error checking and edge case detection, if you need to use it in production:
public String getCodeSourceLocation() {
ClassLoader contextClassLoader = CurrentJARContext.class.getClassLoader();
if(contextClassLoader instanceof URLClassLoader)
{
URLClassLoader classLoader = (URLClassLoader)contextClassLoader;
URL[] urls = classLoader.getURLs();
String externalForm = urls[0].toExternalForm();
externalForm = externalForm.replaceAll("file:\\/", "");
externalForm = externalForm.replaceAll("\\/", "\\" + File.separator);
return externalForm;
}
return null;
}

I found the shortest answer of my own question.
String path = System.getProperty("user.dir");

Related

Access an external jar file in Java

I'm trying to access a specific class from an external jar library.
I have configured the path in my properties file
test-library = file:/Users/test.user/test/library.jar
test-library2 = file:/Users/test.user/test/library2.jar
Then I try to access it from the code but I get ClassNotFoundErrorException or IllegalArgumentException: URI is not absolute when I modify the path as follows
test-library = /Users/test.user/test/library.jar
test-library2 = /Users/test.user/test/library2.jar
When I locate the jar files in the resources folder and specify the path as follows it works fine.
test-library = classpath:library/library.jar
test-library2 = classpath:library/library2.jar
However I need to access the jar files because when the code is deployed we cannot have the jar files in the resource folder but in an external location.
What is the correct way to specify the path of the external jar files so java could find the classes I need?
This is the code where I'm invoking the external libraries and as I said before it works fine if the jar files are in the resource folder but I need to access the jar files from an external location in the machine.
#Value("${test-library}")
String library;
#Value("${test-library2}")
String library2;
public String testMethod(String text1, String text2) {
try {
log.info("[testMethod] start process");
URLClassLoader urlClassLoader =
new URLClassLoader(
new URL[] {URI.create(library).toURL(), URI.create(library2).toURL()},
this.getClass().getClassLoader());
Class<?> classInstance = Class.forName("pro.test.service.TestService", true, urlClassLoader);
Method getInstanceMethod = classInstance.getMethod("getInstance", String.class, String.class);
Object instance = getInstanceMethod.invoke(null, data1, data2);
Method libraryMethod = classInstance.getMethod("libraryMethod", String.class, String.class);
log.info("[testMethod] end process");
return (String) libraryMethod.invoke(instance, text1, text2);
} catch (Exception e) {
log.error("Error testing library method: ", e);
throw e;
}
}```
Reading the documentation of URLClassLoader we find:
This class loader is used to load classes and resources from a search path of URLs referring to both JAR files and directories. Any jar: scheme URL (see JarURLConnection) is assumed to refer to a JAR file.
and following the above link to JarURLConnection:
The syntax of a JAR URL is:
jar:<url>!/{entry}
. . . If the entry name is omitted, the URL refers to the whole JAR file: jar:http://www.example.com/bar/baz.jar!/ ยน
Putting these together, we get, for the first JAR posted in question:
jar:file:/Users/test.user/test/library.jar!/
1 address changed from foo to example since the first is not accepted by StackOverflow (apparently even not inside a quoted code)

Path of the folder inside the jar file

I have jar file langdetect.jar.
It has a hierarchy shown in image
There is a class LanguageDetection at com/langdetect package.
I need to access the path of the profiles.sm folder from above class while executing the jar file.
Thanks in advance.
Jars are nothing else than Zip files and Java provides support for handling those.
Java 6 (and earlier)
You can open the jar file as a ZipFile and iterate over the entries of it. Each entry has a full path name inside the file, there is no such thing as relative path names. Though you have to take care, that all entries - although being absolute in the zip file - do not start with a '/', if you need this, you have to add it. The following snippet will get you the path of a class file. The className has to end with .class, i.e. LanguageDetection.class
String getPath(String jar, String className) throws IOException {
final ZipFile zf = new ZipFile(jar);
try {
for (ZipEntry ze : Collections.list(zf.entries())) {
final String path = ze.getName();
if (path.endsWith(className)) {
final StringBuilder buf = new StringBuilder(path);
buf.delete(path.lastIndexOf('/'), path.length()); //removes the name of the class to get the path only
if (!path.startsWith("/")) { //you may omit this part if leading / is not required
buf.insert(0, '/');
}
return buf.toString();
}
}
} finally {
zf.close();
}
return null;
}
Java 7/8
You may open the JAR file using the Java7 FileSystem support for JAR files. This allows you to operate on the jar file as if it would be normal FileSystem. So you could walk the fileTree until you have found your file and the get the Path from it. The following example uses Java8 Streams and Lambdas, a version for Java7 could be derived from this but would be a bit larger.
Path jarFile = ...;
Map<String, String> env = new HashMap<String, String>() {{
put("create", "false");
}};
try(FileSystem zipFs = newFileSystem(URI.create("jar:" + jarFileFile.toUri()), env)) {
Optional<Path> path = Files.walk(zipFs.getPath("/"))
.filter(p -> p.getFileName().toString().startsWith("LanguageDetection"))
.map(Path::getParent)
.findFirst();
path.ifPresent(System.out::println);
}
Your particular Problem
The above solutions are for finding the path inside a Jar or Zip, but may possibly not be the solution to your problem.
Im not sure, whether I understand your problem correctly. As far as I see it, you'd like to have access to the path inside the classfolder for any purpose. The problem with that is, that the Class/Resource lookup mechanism doesn't apply to folders, only files. The concept that is close is a package, but that is always bound to a class.
So you always need a concrete file to be accessed via getResource() method. For example MyClass.class.getResource(/path/to/resource.txt).
If the resources are located in a profiles.sm folder relative to a class and its package, i.e. in /com/languagedetect/profile.sm/ you could build the path from the reference class, for example the class LanguageDetection in that package and derive the absolute path from this to the profiles.sm path:
String basePath = "/" + LanguageDetection.class.getPackage().getName().replaceAll("\\.", "/") + "/profiles.sm/";
URL resource = LanguageDetection.class.getResource(basePath + "myResource.txt");
If there is only one profiles.sm in the root of the jar, simply go for
String basePath = "/profiles.sm/";
URL resource = LanguageDetection.class.getResource(basePath + "myResource.txt");
If you have multiple jars with a resource in /profiles.sm, you could gain access to all of those via the classloader and then extract the Jar file from the URL of the class
for(URL u : Collections.list(LanguageDetection.class.getClassLoader().getResources("/profiles.sm/yourResource"))){
System.out.println(u);
}
In any case it's not possible without accessing the zip/jar file to browse the contents of this path or folder because Java does not support browsing for classes or resources inside a package/folder in classpath. You may use the Reflections lib for that or extend the ClassLoader example above by additionally reading the content of the detected jars using the zip example from above.

How to Play .wav file when your execute a jar file in java. [duplicate]

In my application I load resources in this manner:
WinProcessor.class.getResource("repository").toString();
and this gives me:
file:/root/app/repository (and I replace "file:" with empty string)
This works fine when I run my application from the IDE, but when I run the jar of my application:
java -jar app.jar
The path becomes:
jar:/root/app.jar!/repository
is there any way to solve this problem?
I'll use the "repository" dir name in order to create this:
ConfigurationContext ctx = (ConfigurationContext) ConfigurationContextFactory.createConfigurationContextFromFileSystem(repositoryString, null);
In the same manner, I'll get one file name (instead of a dir) and I'll use it this way:
System.setProperty("javax.net.ssl.trustStore", fileNameString)
It sounds like you're then trying to load the resource using a FileInputStream or something like that. Don't do that: instead of calling getResource, call getResourceAsStream and read the data from that.
(You could load the resources from the URL instead, but calling getResourceAsStream is a bit more convenient.)
EDIT: Having seen your updated answer, it seems other bits of code rely on the data being in a physical single file in the file system. The answer is therefore not to bundle it in a jar file in the first place. You could check whether it's in a separate file, and if not extract it to a temporary file, but that's pretty hacky IMO.
When running code using java -jar app.jar, java uses ONLY the class path defined in the manifest of the JAR file (i.e. Class-Path attribute). If the class is in app.jar, or the class is in the class path set in the Class-Path attribute of the JAR's manifest, you can load that class using the following code snippet, where the className is the fully-qualified class name.
final String classAsPath = className.replace('.', '/') + ".class";
final InputStream input = ClassLoader.getSystemResourceAsStream( path/to/class );
Now if the class is not part of the JAR, and it isn't in the manifest's Class-Path, then the class loader won't find it. Instead, you can use the URLClassLoader, with some care to deal with differences between windows and Unix/Linux/MacOSX.
// the class to load
final String classAsPath = className.replace('.', '/') + ".class";
// the URL to the `app.jar` file (Windows and Unix/Linux/MacOSX below)
final URL url = new URL( "file", null, "///C:/Users/diffusive/app.jar" );
//final URL url = new URL( "file", null, "/Users/diffusive/app.jar" );
// create the class loader with the JAR file
final URLClassLoader urlClassLoader = new URLClassLoader( new URL[] { url } );
// grab the resource, through, this time from the `URLClassLoader` object
// rather than from the `ClassLoader` class
final InputStream input = urlClassLoader.getResourceAsStream( classAsPath );
In both examples you'll need to deal with the exceptions, and the fact that the input stream is null if the resource can't be found. Also, if you need to get the InputStream into a byte[], you can use Apache's commons IOUtils.toByteArray(...). And, if you then want a Class, you can use the class loader's defineClass(...) method, which accepts the byte[].
You can find this code in a ClassLoaderUtils class in the Diffusive source code, which you can find on SourceForge at github.com/robphilipp/diffusive
And a method to create URL for Windows and Unix/Linux/MacOSX from relative and absolute paths in RestfulDiffuserManagerResource.createJarClassPath(...)
Construct a URL, you can then load a resource (even in a jar file) using the openStream method.

Relative to absolute path in java

I have have a file that I want to use in my project which is in the resources package
src.res
Following what was stated in this answer, I believe that my code is valid.
File fil = new File("/res/t2.nii");
// Prints C:\\res\\t2.nii
System.out.println(fil.getAbsolutePath());
The problem is that I that file is in my projects file not there, so I get an Exception.
How am I suppose to properly convert from relative path to absolute?
Try with directory first that will provide you absolute path of directory then use file.exists() method to check for file existence.
File fil = new File("res"); // no forward slash in the beginning
System.out.println(fil.getAbsolutePath()); // Absolute path of res folder
Find more variants of File Path & Operations
Must read Oracle Java Tutorial on What Is a Path? (And Other File System Facts)
A path is either relative or absolute.
An absolute path always contains the root element and the complete directory list required to locate the file.
For example, /res/images is an absolute path.
A relative path needs to be combined with another path in order to access a file.
For example, res/images is a relative path. Without more information, a program cannot reliably locate the res/images directory in the file system.
Since you are using a Java package, you must to use a class loader if you want to load a resource. e.g.:
URL url = ClassLoader.getSystemResource("res/t2.nii");
if (url != null) {
File file = new File(url.toURI());
System.out.println(file.getAbsolutePath());
}
You can notice that ClassLoader.getSystemResource("res/t2.nii") returns URL object for reading the resource, or null if the resource could not be found. The next line convertes the given URL into an abstract pathname.
See more in Preferred way of loading resources in Java.
validate with
if (fil.exists()) { }
before and check if it really exist. if not then you can get the current path with
System.getProperty("user.dir"));
to validate that you are starting fromt he proper path.
if you really want to access the path you shouldnt use absolut pathes / since it will as explained start from the root of your Harddisk.
you can get the absolut path of the res folder by using this what my poster was writte in the previous answer:
File fil = new File("res");
System.out.println(fil.getAbsolutePath());

How to get absolute path to file in /resources folder of your project

Assume standard maven setup.
Say in your resources folder you have a file abc.
In Java, how can I get absolute path to the file please?
The proper way that actually works:
URL resource = YourClass.class.getResource("abc");
Paths.get(resource.toURI()).toFile();
It doesn't matter now where the file in the classpath physically is, it will be found as long as the resource is actually a file and not a JAR entry.
(The seemingly obvious new File(resource.getPath()) doesn't work for all paths! The path is still URL-encoded!)
You can use ClassLoader.getResource method to get the correct resource.
URL res = getClass().getClassLoader().getResource("abc.txt");
File file = Paths.get(res.toURI()).toFile();
String absolutePath = file.getAbsolutePath();
OR
Although this may not work all the time, a simpler solution -
You can create a File object and use getAbsolutePath method:
File file = new File("resources/abc.txt");
String absolutePath = file.getAbsolutePath();
You need to specifie path started from /
URL resource = YourClass.class.getResource("/abc");
Paths.get(resource.toURI()).toFile();
Create the classLoader instance of the class you need, then you can access the files or resources easily.
now you access path using getPath() method of that class.
ClassLoader classLoader = getClass().getClassLoader();
String path = classLoader.getResource("chromedriver.exe").getPath();
System.out.println(path);
There are two problems on our way to the absolute path:
The placement found will be not where the source files lie, but
where the class is saved. And the resource folder almost surely will lie somewhere in
the source folder of the project.
The same functions for retrieving the resource work differently if the class runs in a plugin or in a package directly in the workspace.
The following code will give us all useful paths:
URL localPackage = this.getClass().getResource("");
URL urlLoader = YourClassName.class.getProtectionDomain().getCodeSource().getLocation();
String localDir = localPackage.getPath();
String loaderDir = urlLoader.getPath();
System.out.printf("loaderDir = %s\n localDir = %s\n", loaderDir, localDir);
Here both functions that can be used for localization of the resource folder are researched. As for class, it can be got in either way, statically or dynamically.
If the project is not in the plugin, the code if run in JUnit, will print:
loaderDir = /C:.../ws/source.dir/target/test-classes/
localDir = /C:.../ws/source.dir/target/test-classes/package/
So, to get to src/rest/resources we should go up and down the file tree. Both methods can be used. Notice, we can't use getResource(resourceFolderName), for that folder is not in the target folder. Nobody puts resources in the created folders, I hope.
If the class is in the package that is in the plugin, the output of the same test will be:
loaderDir = /C:.../ws/plugin/bin/
localDir = /C:.../ws/plugin/bin/package/
So, again we should go up and down the folder tree.
The most interesting is the case when the package is launched in the plugin. As JUnit plugin test, for our example. The output is:
loaderDir = /C:.../ws/plugin/
localDir = /package/
Here we can get the absolute path only combining the results of both functions. And it is not enough. Between them we should put the local path of the place where the classes packages are, relatively to the plugin folder. Probably, you will have to insert something as src or src/test/resource here.
You can insert the code into yours and see the paths that you have.
To return a file or filepath
URL resource = YourClass.class.getResource("abc");
File file = Paths.get(resource.toURI()).toFile(); // return a file
String filepath = Paths.get(resource.toURI()).toFile().getAbsolutePath(); // return file path

Categories