Load class within Jar file and get it's path - java

I know there are already a lot similar questions here, but I couldn't get any smarter form them. I want to load a class inside a jar file, at this point this is no problem, but when I want to pass the path to my own ClassLoader it throws an exception it cannot find the class. Is it possible to load a class inside a jar using an absolute path? For instance,Class cls = loader.loadClass(/path/MyPlugin.jar/MyPlugin.class);
But when I do this:
File test = new File("path/plugins/MyPlugin.jar/MyPlugin.class");
System.out.println(test.exists());
It prints out false. I tried using MyPlugin.jar!/MyPlugin.class or MyPlugin.jar.jar!MyPlugin.class which i've seen sometimes on the web, even though i don't really know what it means...
When I do this it finds the class:
URLClassLoader loader = new URLClassLoader(new URL[] { "path/plugins/MyPlugin.jar" });
Class cl = loader.loadClass("MyPlugin");
But now, how can I receive the path? Something like URL url = cl.getResource("MyPlugin"); (which gives back a null)

You can obtain URLs to classpath resources using ClassLoader.getResources. To find a jar with specific class, you may use the following
URL url = classLoader.getResource("com/example/SomeClass.class");
JarURLConnection connection = (JarURLConnection) url.openConnection();
JarFile file = connection.getJarFile();
String jarPath = file.getName();
where classLoader is any classloader capable of finding the class you want to load. If the jar is a part of your application's classpath, you may use system classloader:
ClassLoader classLoader = ClassLoader.getSystemClassloader();
Otherwise, you need to know the jar file location beforehand, and create an instance of URLClassLoader, passing the jar in the constructor:
ClassLoader classLoader = new URLClassLoader(new URL[]{new URL("path/to/the/jar/file.jar")});
and then use it to load your class.

If you want to access a file in your jar file you have to put it in the same directory as the class files are.
For example if Main.class is in bin/my/pkg/Main.class you can store your MyPlugin.class in the same directory (bin/my/pkg/MyPlugin.class) and then, if you want to access that file use
URL url = Main.getResource("MyPlugin.class");
Which uses the location of Main.class in your project as root.
Hope it helps!

Related

URLClassLoader trying to get a class from external jar always returning null

I am trying to load a class from a jar that is sitting in a directory.
The structure of the class I am trying to grab is as follow:
myapp.jar
|__META-INF
|__com
|__myapp
|__config
|__PlumberConfig.class
This is how I tried to grab the class:
File file = new File("C:/_workspace/_jar/myapp.jar");
URL url = file.toURI().toURL();
URL[] urls = new URL[]{url};
URLClassLoader ucl = new URLClassLoader(urls, ClassLoader.getSystemClassLoader());
LOG.info("URLClassLoader: {}", ucl.getName()); // here always null
Class c = ucl.loadClass("com.myapp.config.PlumberConfig");
The result of new URLClassLoader() is always null hence I cannot go further from this point.
I double-checked everything (the path, name of the jar, and location of the class itself) but seems I am still missing something.
Your code is working but the method getName() is not defined on URLClassLoader. Try ucl.getURLs() instead. Than it should work as expected.

Java loading a resource from outside the classpath (pentaho)

I am a couple of weeks into Java programming and are trying to get the pentao report definition from a folder that is outside the class path, but have so far been unsuccessful.
The following successfully loads the definition from a folder contained in the class path, however I am unable to figure out how to get it from an absolute path outside the class path:
// Parse the report file
final URL reportDefinitionURL = classloader.getResource("some/path/inclass/Sample1.prpt");
final ResourceManager resourceManager = new ResourceManager();
final Resource directly = resourceManager.createDirectly(reportDefinitionURL, MasterReport.class);
return (MasterReport) directly.getResource();
I am not sure if this is pentaho-specific or a generic Java issue, but how can I get the file definition based on a absolute path (linux) which is not located in the class path such as
"/usr/share/pentaho/Sample1.prpt" ?
I have tried this:
File file = new File("/usr/share/pentaho/");
URL url = file.toURI().toURL();
URL[] urls = new URL[]{url};
ClassLoader cl = new URLClassLoader(urls);
final URL reportDefinitionURL = cl.getResource("Sample1.prpt");
I have also tried including the external path at runtime but that does not appear to work either:
java -cp ./lib/*:/usr/share/pentaho/*.prpt ...
Any assistance is greatly appreciated !
Default system class loader will look for resources only in the class path. If u know the absolute path, it would be easier to create the URL object directly:
URL reportDefinitionURL = new URL("file:/tmp/Sample1.prpt");
I am not familiar with the pentaho api's, so not sure how the following api works.
resourceMgr.createDirectly(reportDefinitionURL, MasterReport.class);
In last line it is returning an instance of "MasterReport", so "MasterReport.class" should be there in your class path.
EDIT:
I just looked at this pentaho wiki - http://wiki.pentaho.com/display/Reporting/Using+the+DocumentBundle+Reader+and+Writer
Looks like the createDirectly() apis can take a file object
File reportDefinitionFile = new File ("/tmp/Sample1.prpt");
resManager.createDirectly(reportDefinitionFile, MyClass.class);

getResourceAsStream in dynamically loaded jar

I kow there are dozens (if not hundreds) questions about Java's getResource/getResourceAsStream but i did not find any answers to my problem.
I load jars dynamically with: (String path is given)
File jar = new File(path);
URL url = new URL("file", "localhost", jar.getAbsolutePath());
URLClassLoader loader = new URLClassLoader(new URL[] { url });
c = loader.loadClass(name);
Then within the jar i try to load a resource in the jar. This resource clearly exists in the jar and the whole procedure works if I just run the whole thing with a class loader in Eclipse. In a jar it does not work.$
getClass().getResourceAsStream("resource.dat");
I tried every possible combination of /packageName/resource.dat, packageName/resource.dat, /resource.dat and resource.dat. They all throw a stream closed Exception.
The I tried debugging and ended up printing the URL of these files loaded via getClass().getResource(path)
This led to following URL and it does not look normal to me. Is it supposed to say "localhostC:..."?
jar:file://localhostC:\Users\******\export.jar!/packageName/resource.dat
Converting this URL also throws an Exception (URISyntaxException).
Is this URL really broken or am I just doing something wrong?
Try changing the line:
URL url = new URL("file", "localhost", jar.getAbsolutePath());
to
URL url = new URL("file", null, jar.getAbsolutePath());
The host parameter in the URL constructor is not applicable in this case.
First, the File class has a toURI() method, so the preferred way to get a URL pointing to a file is:
URL url = new File(path).toURI().toURL();
So using this, the class loader:
File jar = new File(path);
URLClassLoader loader = new URLClassLoader(new URL[] { jar.toURI().toURL() });
Next, when you want to load a resource for the jar, use a Class that is originating from the jar, so if you already loaded the Class c:
Class<?> c = loader.loadClass(classPathAndName);
URL resource = c.getResource("data.txt");
This will result in something like:
jar:file:/C:/test/testjar.jar!/testpkg/data.txt
Alternatively you can use the ClassLoader to get the resource like:
loader.getResoure(packageAndResourceName);
But note that this quoting from the javadoc:
This method will first search the parent class loader for the resource; if the parent is null the path of the class loader built-in to the virtual machine is searched. That failing, this method will invoke findResource(String) to find the resource.

how to get inputstream from class file existed in other project

I am trying to get inputstream from class file of the other project.
I am using eclipse. The output folder is:
mycurrentproject/WebContent/WEB-INF/classes.
The export library folder is:
mycurrentproject/WebContent/WEB-INF/lib.
When I print "java.class.path", I got this:
D:\apache-tomcat-7.0.42\bin\bootstrap.jar;D:\apache-tomcat-7.0.42\bin\tomcat-juli.jar;
My environment variable of CLASS PATH of WINDOWS system is:
.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;D:\work\workspace\myjar
My code in package action to get resource stream is:
classfilePath = "/cc/Person.class";
InputStream isInputStream = ModifyMethodTest.class.getResourceAsStream(classfilePath);
Package action is outputed in "mycurrentproject/WebContent/WEB-INF/classes". action.jar is exported in "mycurrentproject/WebContent/WEB-INF/lib".
When cc/Person.class in "mycurrentproject/WebContent/WEB-INF/classes", I got right result. When cc/Person.class in "mycurrentproject/WebContent/WEB-INF/lib" or in "D:\work\workspace\myjar". isInputStream got null. I want to get inputstream form a class file in the other project. The class file maybe in a folder or in a jar file in the target project folder. There should be many classes or jar files in that project. How to do that? For now, and for simple, I test my idea as above to put cc/Person.class in "D:\work\workspace\myjar". But It failed either. Any one have similar experience or advices? Thanks.
EDIT:
classfilePath ="file:D:/work/workspace/myjar/cc/Person.class";
URL[] urls = new URL[] { new URL(classfilePath) };
URLClassLoader ucl = new URLClassLoader(urls);
InputStream isInputStream = ucl.getResourceAsStream(classfilePath);
Here isInputStream still got null. The parameter of getResourceAsStream() is String name. What could be? Something like relative path? Any references?
EDIT2:
It works with code as follow:
String Path1 = "file:D:/";
String Path2 = "work/workspace/myjar/cc/Person.class";
URL[] urls = new URL[] { new URL(Path1) };
URLClassLoader ucl = new URLClassLoader(urls);
InputStream isInputStream = ucl.getResourceAsStream(Path2);
Use an URLClassLoader. Once you've established it, call:
getResourceAsStream("/work/workspace/myjar/cc/Person.class")
For the InputStream.

have a file in the classloader's root path, how to create it

File f = new File(path)
How to give the path parameter in this case?
You mean something like this?
URL resource = Thread.currentThread().getContextClassLoader().getResource("config.properties");
File f = new File(resource.toURI());
In principle, you need to know from where the classloader loads its resources. This is classloader-dependent, and most types of classloader don't use files at all. If you have an URLClassLoader (which fortunately is quite often), you can ask it about its URLs, and look if there is one file: URL. Then use this URL as a base.
If your Classloader has no file: URL, obviously you have no chance.
But I think most probably you are not doing the right thing - what do you really want to do?
You could use a better option and go for java.net.URLClassLoader.
This class loader is used to load classes and resources from a search path of URLs referring to both JAR files and directories.
A URLClassLoader can be used to load classes in any directory.
Check out this example
// Create a File object on the root of the directory containing the class file
File file = new File("c:\\myclasses\\");
try {
// Convert File to a URL
URL url = file.toURL(); // file:/c:/myclasses/
URL[] urls = new URL[]{url};
// Create a new class loader with the directory
ClassLoader cl = new URLClassLoader(urls);
// Load in the class; MyClass.class should be located in
// the directory file:/c:/myclasses/com/mycompany
Class cls = cl.loadClass("com.mycompany.MyClass");
} catch (MalformedURLException e) {
} catch (ClassNotFoundException e) {
}
Also, have a look at File ClassLoader in Java

Categories

Resources