How to read a file in another jar file? - java

I am running a GUI application (A.jar). Then I add a plugin (B.jar) to this GUI(A.jar).
Now I want to access the manifest.mf file in B.jar. I tried B.class.getResourceAsInputStream("/META-INF/MANIFEST.MF"). However, what I got is the manifest.mf in A.jar, not in B.jar.
Anyone can give me some hints on this problem? Thanks so much.

It is the case that the general class loader will take the path the comes first on the class path, and evidently A.jar comes first, before B.jar.
String someUniqueResourceInBJar = "...";
URL url = B.class.getResource(someUniqueResourceInBJar);
url = new URL(url.getPath().replaceFirst(someUniqueResourceInBJar + "$", "")
+ "META-INF/MANIFEST.MF";
url.openStream();
The url will be something like "jar:file://.../B.jar!META-INF/MANIFEST.MF".
Alternatively getting the class URL:
URL url = b.class.getProtectionDomain().getCodeSource().getLocation();

Related

Java Class Loader not able to read resource

I have a file in structure. projectName/src/config/keyfiles/file and my code is in folder projectName/src/main/java/customProject/package/filename.java
I am trying to read my file with class loader like.
URL url = CommonUtil.class.getClassLoader().getResource(filename);
but every time I am getting url as null. passed filename is ./keyfiles/file.
Please let me know where I am going wrong
To make sure "where you are" in the directory tree, do the following:
URL url = YourMainClass.class.getClassLoader().getResource(".");
System.out.printf("%s\n", url);
Then you will know why you can't get your file

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.

ClassNotFound With URLClassLoader

I currently have the following directory tree structure:
CLASSES
-> ClassOne
->package
-> my
->App.class
I would like to load the App.class from my local drive. I looked around, particularly stackoverflow, and most seem to suggest that I should use the URLClassLoader.
In order to do this, I used this following code:
However, I get a ClassNotFoundError. Can anybody help me please.
String url = "file://" + classOneFolder.getAbsolutePath(); //Where classesFolder is a File representing the ClassOne directory
URL[] urls = {new URL(url)};
urlClassLoader = URLClassLoader.newInstance(urls);
//class loader needs the fully classified class name. Therefore:
Class appClass = urlClassLoader.loadClass("package.my.App");
I would suggest you use classOneFolder.toURI().toURL() instead of building the URL yourself as a String and then recreate a URL from it. On some systems (like Windows) you need to add another slash in front on the absolute filename for a valid URL. Using File.toURI().toURL() should always build a correct URL.

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

Creating a URL object with a relative path

I am creating a Swing application with a JEditorPane that should display an HTML file named url1.html stored locally in the page folder in the root folder of the project.
I have instantiated the following String object
final String pagePath = "./page/";
and in order to be displayed by the JEditorPane pane I have created the following URL object:
URL url1 = new URL("file:///"+pagePath+"url1.html");
However when the setPage() method is called with the created URL object as a parameter:
pagePane.setPage(url1);
it throws me a java.io.FileNotFoundException error.
It seems that there is something wrong with the way url1 has been constructed. Anyone knows a solution to this problem?
The solution is to find an absolute path to url1.html make an object of java.io.File on it, and then use toURI().toURL() combination:
URL url1 = (new java.io.File(absolutePathToHTMLFile)).toURI().toURL();
Assuming if the current directory is the root of page, you can pass a relative path to File:
URL url1 = (new java.io.File("page/url1.html")).toURI().toURL();
or
URL url1 = (new java.io.File(new java.io.File("page"), "url1.html")).toURI().toURL();
But this will depend on where you run the application from. I would make it taking the root directory as a command-line argument if it is the only configurable option for the app, or from a configuration file, if it has one.
The another solution is to put the html file as a resource into the jar file of your application.
To load a resource from the classpath (as khachik mentioned) you can do the following:
URL url = getClass().getResource("page/url1.html");
or from a static context:
URL url = Thread.currentThread().getContextClassLoader().getResource("page/url1.html");
So in the case above, using a Maven structure, the HTML page would be at a location such as this:
C:/myProject/src/main/resources/page/url1.html
I would try the following
URL url = new URL("file", "", pagePath+"url1.html");
I believe by concatenating the whole string, you are running into problems. Let me know, if that helped

Categories