01 Feb, 2010, Kaeden wrote in the 1st comment:
Votes: 0
Hello,

Suppose I have a main class, an interface, and a few concrete implementations of the interface all in the same directory. When the main class is run, it checks the local directory for any of the implementation .class files and loads them with URLClassLoaders. It works fine.

I then pack a manifest file, the main .class, and the interface .class into an executable .jar file placed in the same directory. I leave the implementation .class files outside of the .jar. This time, when the .jar is run, it finds the implementation .class files, but it throws a ClassNotFound exception when it tries to load them. I suspect the reason why is relatively simple, but I can't seem to figure it out. Does anyone have a clue as to what might be wrong?

Thanks!

–Kaeden
01 Feb, 2010, David Haley wrote in the 2nd comment:
Votes: 0
Kaeden said:
it finds the implementation .class files

What exactly do you mean by this? Where is it finding them? Do you have the full package structure set up outside the .jar that it should be looking into? I'm not sure what you mean by it being able to "find" them but not load them.

You might also have to try setting the classpath yourself when you try to run the .jar, to also contain wherever you put your other .class files.
01 Feb, 2010, Kaeden wrote in the 3rd comment:
Votes: 0
(I'm substituting animal stuff in place of other class names for sake of simplicity)

My program has a Main class, an Animal interface, and a Cat class that implements the Animal interface as well as a Dog class that implements the Animal interface. When everything is compiled, I have Main.class, Animal.class, Cat.class, and Dog.class. Cat.class and Dog.class were the "implementation .class files" that I meant.

When Main.class, Animal.class, Cat.class, and Dog.class are all in the same directory, the Main.class is able to search the local directory and use classloaders to load instances of Cat and Dog.

However, when I have a manifest, Main.class, and Animal.class in an executable .jar, but Cat.class and Dog.class are outside of the .jar in the same directory, the program is unable to load Cat.class and Dog.class. When the .jar is executed, it gets the directory it is located in, then it iterates through all of the files in the directory. If a file ends with ".class", it then tries to load it with a classloader. I'm not using any packages other than the default package in Eclipse. Are packages important with classloading stuff?

I'm not sure if I explained it any better but I will try to clarify further if needed. The help is much appreciated.
02 Feb, 2010, David Haley wrote in the 4th comment:
Votes: 0
Hmm, this is starting to get a little beyond what I've played with class files in and out of jars. So I'm kind of exploring this issue at the same time.

First off, what does the manifest in the .jar say?

Packages are important when it comes to classloading stuff. When you have /foo/bar on your classpath, and you look for the class "kaeden.stuff.animals.Dog", then it goes to find that in /foo/bar/kaeden/stuff/animals/Dog.class. But if you've put everything in the default package, then you don't really have packages anymore.

If you try this on the command line, what do you get?
java -cp . yourjar.jar
where I'm assuming that all of your .class files are in the same directory as your .jar file, and furthermore that everything is in the default package (i.e., not packaged).



It sounds like what you're saying is that you have written code in the .jar to iterate over the directory's contents and load stuff by hand. But that is indeed separate from what the standard classloader does.
03 Feb, 2010, Kaeden wrote in the 5th comment:
Votes: 0
Since I last posted here, I placed everything in a package named "Program". I changed the manifest to "Main-Class: Program.Main" followed by a newline.

I've tried "java -cp . yourjar.jar" with Dog.class and Cat.class alongside the .jar in the same directory. I still get a ClassNotFoundException for both Dog.class and Cat.class.

Yes, the code in the .jar iterates through the directory's contents, checks to see if the file extension is ".class", then it tries to load it with a classloader (the step it fails on when executed from the jar, but not when outside the jar), then it instantiates an object and tests if it's an Animal and so on.

Don't sweat it too much. The reason I needed it for has since disappeared. Though it will still be interesting to know if there's a way to do it. Thanks again for the help.
03 Feb, 2010, David Haley wrote in the 6th comment:
Votes: 0
Well, if you have it in a package called 'Program', then you need to put the class files into ./Program. So you would have,

/your/path/yourjar.jar
and then
/your/path/Program/Dog.class
/your/path/Program/Cat.class

this is what I meant by the package name mattering; class path tells Java where the root for class files is. You still need to have things in the proper structure.

I'm kind of curious why this is happening because I distinctly remember having .jar files with some .class files outside. A .jar is just a collection of .class files after all.
03 Feb, 2010, Kaeden wrote in the 7th comment:
Votes: 0
Tried that too (though it requires slight modification of the Main class inside the .jar to look inside the Program folder, otherwise it won't find Dog.class and Cat.class). Same problem.
18 Feb, 2010, Zod wrote in the 8th comment:
Votes: 0
Kaeden said:
then it tries to load it with a classloader


Can you be more specific about "a classloader" ?
Where did the classloader come from?

It sounds like the classloader you're trying to use doesn't not search in the directory that holds Cat and Dog classes.
09 Mar, 2010, flumpy wrote in the 9th comment:
Votes: 0
Kaeden said:
Hello,

Suppose I have a main class, an interface, and a few concrete implementations of the interface all in the same directory. When the main class is run, it checks the local directory for any of the implementation .class files and loads them with URLClassLoaders. It works fine.

I then pack a manifest file, the main .class, and the interface .class into an executable .jar file placed in the same directory. I leave the implementation .class files outside of the .jar. This time, when the .jar is run, it finds the implementation .class files, but it throws a ClassNotFound exception when it tries to load them. I suspect the reason why is relatively simple, but I can't seem to figure it out. Does anyone have a clue as to what might be wrong?

Thanks!

–Kaeden


When you include a bunch of class files , you need to specify a root directory of the compiled code (the default package directory) on the classpath. When you are working with Jars, you need to specify the name of the jar file (think of the jar file as being a "directory" and it will make sense). The package of the class needs to match the sub directory structure underneath the default directory for the former, and the directory structure in the jar file for the latter.

For example, you have some classes in a directory called /usr/home/foo, and the class files are located under there in /com/mud/blah/ (fully qualified path would be /usr/home/foo/com/mud/blah), the classes need to have been compiled with the package declaration "package com.mud.blah". You then use these classes by doing an "import com.mud.blah.*".

Likewise, if you have a jar file in /usr/home/foo/lib/foo.jar, you must specify the actual jar file on the classpath. You can then access the classes in that jar in the same way (import).

If you are trying to load them dynamically, your classloader needs to follow the same rules as when you specify these things on the classpath. For example:

import java.net.URLClassLoader;

public class MyTest{

public static void main(String[] args) throws MalformedURLException, ClassNotFoundException, InstantiationException, IllegalAccessException{
URL urls = new URL[]
URL[] urls = {new URL("file:///usr/home/foo/"), new URL("file:///usr/home/foo/lib/foo.jar")};

URLClassLoader classLoader = new URLClassLoader(urls);
Class myClass = classLoader.loadClass("com.mud.blah.SomeClass");
myClass.newInstance();
}
}

NB. The above assumes that SomeClass has a default constructor. You would have to get hold of the correct Constructor object (myClass.getConstructor((Class)paramTypes..)) otherwise.
0.0/9