gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

OffTopic > Java: Read classes from jar

#123408 - Mr Snowflake - Tue Mar 27, 2007 11:22 pm

I'm back with a Java question. I need to be able to read a class from a jar file, because I need to determine it's public functions, public method, public... well everything it's interface delivers to the public :). So my sollution is: Open the jar file with a JarFile object, get the JarEntries, and if they are '.class' write them, using a OutputStream, to a File.createTempFile() and then reflection load them to discover all the public stuff. Is this the way to go, or is my way too complicated and is there an other, easier way?
_________________
http://www.mrsnowflake.be

#123413 - keldon - Wed Mar 28, 2007 12:05 am

http://www.javaworld.com/javaworld/javatips/jw-javatip49.html

I had more links but I don't know what happened to them.

#123517 - gauauu - Wed Mar 28, 2007 8:08 pm

Can't you just add a jar file to the classpath, and java will read any classes from it like normal classes. You still might have to read the JarEntries from the jar file to find out what classes were in it, but I don't think you're going to have to go write the classes out to temp files.

#123585 - ps2aich - Thu Mar 29, 2007 9:27 am

You could try to use a separate Classloader for this (in case you know
the fully qualified classnames already, but you can determine them e.g. with the method pointed out by keldon)

Try something like that (I haven't tested this code, simply wrote it as example without syntax checking and whatsoever):
Code:

URL[] urls = new URL[] {"file://c:\\mypath\\myjar.jar"};
URLClassloader classLoader = URLClassLoader.newInstance(urls);

Class class = classLoader.loadClass("com.myCompany.myPackage.MyClass");

#123596 - Mr Snowflake - Thu Mar 29, 2007 1:55 pm

Thanks you all.
Thanks to Keldons link I discovered how to read the classes from the jar files and the page said I should use a custom ClassLoader class to load the classes. So that's what I'm going to do.
I could add them to the classpath, but then I should be able to edit the classpath at runtime and I still need to find out which classes are in the jar. But this method would be better as Java itself will handle the jar reading. So can I change the classpath at runtime?

An other question, but not very related: Can I make a jar file which contains an other jar? I have a jar file with the gnu getopt methods for java. But I need to supplie them with my project, so I would be nicer/easier to get that jar also in the main jar.

Edit: I didn't completely see ps2's reply, but the URL loader thingy does indeed look very easy. So gonna try that. I already saw this method on the Java tutorial/documentation site, iirc, but already forgot about it :).
_________________
http://www.mrsnowflake.be

#123602 - ps2aich - Thu Mar 29, 2007 4:06 pm

Mr Snowflake wrote:

An other question, but not very related: Can I make a jar file which contains an other jar? I have a jar file with the gnu getopt methods for java. But I need to supplie them with my project, so I would be nicer/easier to get that jar also in the main jar.


Hm, you could try a Jar URL to access this jar:-) (excerpt from the java online documentation):
But I never saw this anywhere used, so no idea if it will really work.

Code:
JAR URL
The syntax of a JAR URL is:

jar:<url>!/{entry}

for example:

jar:http://www.foo.com/bar/baz.jar!/COM/foo/Quux.class
jar:file:/export/home/faculty/stansif/public_html/java/applets/image/view.jar!/image.gif


so, if you build an url like this:
Code:
jar:file:c:/mypath/myjar.jar!/innerjar.jar

#123603 - keldon - Thu Mar 29, 2007 4:09 pm

A jar file is an archive; so you can put anything in it. If you want you can have nested jar files inside of nested jar files, all contained within a great big jar file. But you may be required to extract the jar file before delving into the next one.

#123606 - ps2aich - Thu Mar 29, 2007 4:33 pm

keldon wrote:
A jar file is an archive; so you can put anything in it. If you want you can have nested jar files inside of nested jar files, all contained within a great big jar file. But you may be required to extract the jar file before delving into the next one.


I aggree that it perhaps will work with a depth of one (as stated in my last post), but I assume it
will fail further on because I don't know the inner implementation of jar file handling
(a jar is a zip file, so the classloader will have to held the
jar open all the time, and so on, I really dont know the limitations.),
so you simply have to extract it.

Also performance may be a problem, depending on the implementation
of the java vm, since opening a zipstream and accessing an inner jar
has of course some overhead if the stream is not held open, but opened
on each access, until all classes are in memory.

Since 3.2, the Eclipse Framework allows plugins as jars, and they do not recommend placing additional jars into a jar-plugin, but use the older plugin format (plugin is a directory, which contains the plugin jar and any additional needed jars).

#123622 - Mr Snowflake - Thu Mar 29, 2007 5:59 pm

Thanks again.

Yet another problem with the URLClassLoader:
Code:
    Enumeration<JarEntry> jarEntries;
    URL[] urls = null;
    String userDir = System.getProperty("user.dir");
    try{
      urls = new URL[] {new URL("file://"+userDir+"/"+args[0])};
    }catch(MalformedURLException ex){
      System.out.println(ex);
      System.exit(1);
    }
    System.out.println(urls[0].toString());
    URLClassLoader classLoader = new URLClassLoader(urls);//URLClassLoader.newInstance(urls);
    Vector<String> entries = new Vector();
    try{
      //fetch alle jar entries
      JarFile jar = new JarFile(args[0]);
      jarEntries = jar.entries();
      JarEntry jarEntry = null;
      for (; jarEntries.hasMoreElements();){
        jarEntry = (JarEntry)jarEntries.nextElement();
        if(!jarEntry.isDirectory())
          entries.add(jarEntry.getName());
      }
      if(!entries.isEmpty())
        for(String className:entries)
          try{
            System.out.println(className);
            Class classTest = classLoader.loadClass(className);
          }catch(ClassNotFoundException ex){
            System.out.println(ex);
          }
    }catch(IOException ex){
      System.out.println(ex);
    }

This is a test program to test the URLClassLoader. But when I try to load a jar file (java-gnu...jar) and it looks like I'm able to load the jar file from the url, but when I try to load any of the classes in the jar file, they can't be found... and I don't get an error when loading the jar with URLClassLoader.
_________________
http://www.mrsnowflake.be

#123695 - ps2aich - Fri Mar 30, 2007 9:48 am

Mr Snowflake wrote:
Thanks again.

Yet another problem with the URLClassLoader:
This is a test program to test the URLClassLoader. But when I try to load a jar file (java-gnu...jar) and it looks like I'm able to load the jar file from the url, but when I try to load any of the classes in the jar file, they can't be found... and I don't get an error when loading the jar with URLClassLoader.


Hm, the classnames are fully qualified ("com.mypackage.myclass")?
Or does the JarEntry delivers "com/mypackage/myclass.class"? Then you have to convert it to the format needed by the loadClass-Method(fully qualified, packages separated by ".").


Have you tried to close the Jarfile after collecting the entries, and
then create the URLClassloader and access the classes?
Or some basic dummy test, not to work with the JarFile at all,
but simply load a class thats fully qualified name is nown

#123701 - Mr Snowflake - Fri Mar 30, 2007 1:39 pm

ps2aich wrote:
Hm, the classnames are fully qualified ("com.mypackage.myclass")?
Or does the JarEntry delivers "com/mypackage/myclass.class"? Then you have to convert it to the format needed by the loadClass-Method(fully qualified, packages separated by ".").
This sound very logical, I knew I needed fully qualified classnames, but I was mislead by the dir structure inside the jar... Gotta try this one.

Edit: It works now... Such a simple mistake... Ah well, thank you all for helping. I know where to find you with more questions ;).
_________________
http://www.mrsnowflake.be