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.
Related
I'm aware this question has been asked multiple times (such as here), but none of the answers appear to work for me.
This is a homework assignment, I'm supposed to "hack" several class files via the reflection API, but I can't even get them to load.
There are three .class files (Inscription.class, Decoder.class, Safe.class) I put in D:\class\. Then I try to load them via an URLClassLoader:
public void Load() throws MalformedURLException {
ClassLoader loader = this.getClass().getClassLoader();
File classFolder = new File("D://class//");
// classFolder.exists() returns true at this point.
URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{classFolder.toURI().toURL()},loader);
// urlClassLoader.classes is empty at this point, which is suspicous
urlClassLoader.loadClass("Safe");
// throws NoClassDefFoundError (wrong name: ea_6_1/Safe)
// Interestingly, it seems to find a package name (ea_6_1)
urlClassLoader.loadClass("ea_6_1.Safe");
// throws ClassNotFoundException
}
I also tried to load the files one by one, but apparently this shouldn't work, since URLClassLoader only accepts directories or JAR files:
URL inscription = loader.getResource("Inscription.class");
URL safe = loader.getResource("Safe.class");
URL decoder = loader.getResource("Decoder.class");
URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{inscription, safe, decoder});
// Exact same behavior as above.
My classpath configuration looks like this:
Is this a configuration issue or am I using the URLClassLoader wrong? Is there maybe another way of loading class files?
It appears someone has moved .class files around, without preserving the required directory structure.
A Java class declared with package ea_6_1; must reside in a directory named ea_6_1 (in every Java implementation I know of, at least).
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.
I'm trying to load a resource (plain text file) from a second JAR that has not be loaded yet. This resource will contain a string representing a class in this second jar which I plan to use.
I'm having trouble finding the correct way to load this resource, and previous similar questions haven't gotten me much further. Here is what I'm working with:
public void readResource() {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
}
I can see in this ClassLoader (which ends up being a WebappClassLoader) has the list of jars in the directory:
jarNames: [com.mysql.jdbc.jar, productivity-common.jar]
jarPath: /WEB-INF/lib
When I try to load up the file using the ClassLoader, I'm getting a NullPointerException:
String path = loader.getResource("com/productivity/common/META-INF/providers/hello.txt").getPath();
If this would work, my next step would be reading the value in this file using an InputStream, and trying to create a new instance of a class matching that value from the same second jar. From what I'm reading, I would use the path to that class and use Class.forName("value").newInstance(), but I'm not confident that's right either.
Any assistance would be greatly appreciated. I'm trying to learn how ClassLoaders work and writing this (what should be simple) project to help.
Let me assume you have two resource files with same name "spring/label.properties" stored in two different jar files.
You can use following code to find list of all files from class path, then filter based on path.
Enumeration<URL> en = this.getClass().getClassLoader().getResources("spring/label.properties");
while(en.hasMoreElements()){
URL url = en.nextElement();
//Print all path to visualize the path
System.out.println(url.getPath());
if(url.getPath().contains("my-jar")){ // This can be jar name
BufferedReader reader = new BufferedReader(new InputStreamReader(en.nextElement().openStream()));
String str = null;
while((str = reader.readLine())!=null){
// Now you can do anything with the content.
System.out.println(str);
}
}
}
Does that help?
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();
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