![]() |
|
|
|||||||
![]() |
Java - Reflection - Class Loading and NoClassDefFoundError |
|
|
Thread Tools | Search this Thread |
|
|
#1 |
|
Hi all,
I hope this isn't too obvious a question - I cannot find an answer anywhere. I have some classes I need to load using reflection. These classes are generated and compiled at runtime by my app, so the only info I have about them is their location. I therefore get a list of the filenames, and loop through these using a URLClassLoader to load them in. However, I am obtaining a NoClassDefFoundError due to the dependancies between classes. For instance, say we have (interface) ClassA, and ClassB. ClassB implements ClassA. No matter which order I load these, I get the NoClassDefFoundError when loading ClassB. I really don't want to have to try to force these classes to be on the classpath - that wouldn't work anyway as when they are generated, they are in their package directory structure. They have to be loaded straight after creation and their complilation, so I cannot restart my app either. Can anyone assist me with this? Many thanks Lee. lee@datadialogs.com |
|
|
|
|
#2 |
|
Posts: n/a
|
Lee,
Are you loading them through the same class loader? Or are you consing up a new URLClassLoader for each new file? In general the latter won't work. /jim g spamBucket@agile-it.com |
|
|
|
#3 |
|
Posts: n/a
|
Hi,
I've tried both - my initial implementation was to use the same URLClassLoader for all the files. This failed, so I switched to creating a new ClassLoader each time, passing in the ClassLoader from the previously loaded class as the parent each time. This has no apparent effect! Code Snippet (simplified to just show 2 classes being loaded) File file = new File("C:\\"); try { // Convert File to a URL URL url = file.toURL(); URL[] urls = new URL[]{url}; // Create a new class loader with the directory ClassLoader cl = new URLClassLoader(urls); Class cls = cl.loadClass("classname1"); ClassLoader parentLoader = cls.getClassLoader(); URLClassLoader cl2 = new URLClassLoader(new URL[]{file.toURL()}, parentLoader); Class cls1 = cl2.loadClass("classname2"); } Whether I use cl or cl2 to load classname2, I get the same error - classname2 implements classname1 and I get NoClassDefFoundError. ta Lee. wrote: > Lee, > > Are you loading them through the same class loader? > > Or are you consing up a new URLClassLoader for each new file? > > In general the latter won't work. > > /jim g Lee |
|
|
|
#4 |
|
Posts: n/a
|
Lee wrote:
> ClassLoader cl = new URLClassLoader(urls); > Class cls = cl.loadClass("classname1"); > ClassLoader parentLoader = cls.getClassLoader(); > URLClassLoader cl2 = new URLClassLoader(new URL[]{file.toURL()}, > parentLoader); I don't understand what/why you are doing with the parent classloader here -- it doesn't make any sense at all at first glance. What you should be doing is: Create a classloader, probably an instance of URLClassLoader. You shouldn't specify a parent unless you /yourself/ want to build a tree of classloaders (which sounds unlikely for this application). It should be configured so that all the classfiles you are interested in are on its own "classpath". The use it to load classes. It is, as far as I know, a mistake to call the URLClassloader's loadClass() directly (in fact it's impossible, so your sample code must not be very representative of what you are really doing). You should always use Class.forName(). URL urls = ... Classloader loader = new URLClassLoader(urls); Class cl1 = Class.findClass("class1", true, loader); Class cl2 = Class.findClass("class2", true, loader); Simple as that... Incidentally, if code in class1 or class2 uses Class.forName(String) -- i.e. the single argument form -- then that will automatically use the custom URLClassLoader. You only need to specify the classloader explicitly in code which was not loaded via that classloader. -- chris Chris Uppal |
|
|
|
#5 |
|
Posts: n/a
|
Chris,
Thanks for your input. The reason that I implemented code using a parent classloader is that's what half the websites on this subject suggested doing! I initially implemented this in the much simpler form you suggested, although I was using LoadClass as illustrated in my snippet. I don't know why you think it's impossible to use LoadClass directly - the code snippet I gave you was taken directly from my code, with variable names changed to protect the innocent. It works perfectly providing that I'm not attempting to load a class that implements another. I will now go and try your snippet, to see if it helps. Thanks again and watch this space! Lee. Chris Uppal wrote: > Lee wrote: > > > ClassLoader cl = new URLClassLoader(urls); > > Class cls = cl.loadClass("classname1"); > > ClassLoader parentLoader = cls.getClassLoader(); > > URLClassLoader cl2 = new URLClassLoader(new URL[]{file.toURL()}, > > parentLoader); > > I don't understand what/why you are doing with the parent classloader here -- > it doesn't make any sense at all at first glance. What you should be doing is: > > Create a classloader, probably an instance of URLClassLoader. You shouldn't > specify a parent unless you /yourself/ want to build a tree of classloaders > (which sounds unlikely for this application). It should be configured so that > all the classfiles you are interested in are on its own "classpath". > > The use it to load classes. It is, as far as I know, a mistake to call the > URLClassloader's loadClass() directly (in fact it's impossible, so your sample > code must not be very representative of what you are really doing). You should > always use Class.forName(). > > URL urls = ... > Classloader loader = new URLClassLoader(urls); > Class cl1 = Class.findClass("class1", true, loader); > Class cl2 = Class.findClass("class2", true, loader); > > Simple as that... > > Incidentally, if code in class1 or class2 uses Class.forName(String) -- i.e. > the single argument form -- then that will automatically use the custom > URLClassLoader. You only need to specify the classloader explicitly in code > which was not loaded via that classloader. > > -- chris Lee |
|
|
|
#6 |
|
Posts: n/a
|
Hi, just to clarify - when you say findClass, I'm assuming you mean
forName? Lee wrote: > Chris, > > Thanks for your input. The reason that I implemented code using a > parent classloader is that's what half the websites on this subject > suggested doing! I initially implemented this in the much simpler form > you suggested, although I was using LoadClass as illustrated in my > snippet. I don't know why you think it's impossible to use LoadClass > directly - the code snippet I gave you was taken directly from my code, > with variable names changed to protect the innocent. It works > perfectly providing that I'm not attempting to load a class that > implements another. > > I will now go and try your snippet, to see if it helps. Thanks again > and watch this space! > > Lee. > > > > > Chris Uppal wrote: > > Lee wrote: > > > > > ClassLoader cl = new URLClassLoader(urls); > > > Class cls = cl.loadClass("classname1"); > > > ClassLoader parentLoader = cls.getClassLoader(); > > > URLClassLoader cl2 = new URLClassLoader(new URL[]{file.toURL()}, > > > parentLoader); > > > > I don't understand what/why you are doing with the parent classloader here -- > > it doesn't make any sense at all at first glance. What you should be doing is: > > > > Create a classloader, probably an instance of URLClassLoader. You shouldn't > > specify a parent unless you /yourself/ want to build a tree of classloaders > > (which sounds unlikely for this application). It should be configured so that > > all the classfiles you are interested in are on its own "classpath". > > > > The use it to load classes. It is, as far as I know, a mistake to call the > > URLClassloader's loadClass() directly (in fact it's impossible, so your sample > > code must not be very representative of what you are really doing). You should > > always use Class.forName(). > > > > URL urls = ... > > Classloader loader = new URLClassLoader(urls); > > Class cl1 = Class.findClass("class1", true, loader); > > Class cl2 = Class.findClass("class2", true, loader); > > > > Simple as that... > > > > Incidentally, if code in class1 or class2 uses Class.forName(String) -- i.e. > > the single argument form -- then that will automatically use the custom > > URLClassLoader. You only need to specify the classloader explicitly in code > > which was not loaded via that classloader. > > > > -- chris Lee |
|
|
|
#7 |
|
Posts: n/a
|
Ok, I've had another look through your comments, and I'm a touch
confused. findClass, as a member of Class, is a protected method and therefore I can't call it unless I override it. Also, it's a single argument only, I can't find anything that matches what you have illustrated. I can use forName but the code is not inside Class1 or Class2. Therefore it doesn't work on the second (implementing class). Also, I have to set the initialise boolean parameter to false or it fails for all files. I also note that you mention something about having these files on the classpath. These files will be generated at runtime, and put into a dynamically specified directory. Therefore I cannot add this directory to the classpath. Cheers again. Lee. Lee |
|
|
|
#8 |
|
Posts: n/a
|
Lee wrote:
> Ok, I've had another look through your comments, and I'm a touch > confused. My mistake. I meant Class.forName() wherever I mentioned Class.findClass() (I find Class.forName() a very unintuitive name, and keep substituting a "clearer" one automatically). My apologies for the confusion. [from an earlier post] > I don't know why you think it's impossible to use LoadClass > directly - the code snippet I gave you was taken directly from my code, > with variable names changed to protect the innocent. Again, my mistake -- I was thinking of ClassLoader.findClass() (notice a pattern here ? However, loadClass() is only public in one form (which incidentally, is /not/ the form used as an example in the JavaDoc...) and its other forms (including its "replacement" findClass()) are documented as intended only for the JVM to call, or for classloaders to delegate to their superclass implementations. I'm not sure why loadClass(String) is public. One indication that it probably shouldn't be is that it doesn't work for loading array classes. I believe that we are better off avoiding even the public form. YMMV. [back to the most recent post] > I also note that you mention something about having these files on the > classpath. These files will be generated at runtime, and put into a > dynamically specified directory. Therefore I cannot add this directory > to the classpath. I did put the word "classpath" into scare quotes -- to show that I didn't mean the /real/ classpath. All I meant was the classpath-like sequence of URLs that each URLClassLoader is configured to search. -- chris Chris Uppal |
|
|
|
#9 |
|
Posts: n/a
|
> My mistake. I meant Class.forName() wherever I mentioned Class.findClass() (I > find Class.forName() a very unintuitive name, and keep substituting a "clearer" > one automatically). My apologies for the confusion. No worries, I appreciate your assistance! > However, loadClass() is only public in one form (which incidentally, is /not/ > the form used as an example in the JavaDoc...) and its other forms (including > its "replacement" findClass()) are documented as intended only for the JVM to > call, or for classloaders to delegate to their superclass implementations. I'm > not sure why loadClass(String) is public. One indication that it probably > shouldn't be is that it doesn't work for loading array classes. I believe that > we are better off avoiding even the public form. YMMV. You are probably right, as I can't get it to work! > I did put the word "classpath" into scare quotes -- to show that I didn't mean > the /real/ classpath. All I meant was the classpath-like sequence of URLs that > each URLClassLoader is configured to search. ~ Aha, right you are then, I did worry for a minute! I still can't get it to work though, even with your suggestions! I have a fudgy way to work round the problem at the moment but if you or anyone has any further suggestions I;d be really grateful. Cheers Chris and other poster, Lee. Lee |
|
|
|
#10 |
|
Posts: n/a
|
Lee wrote:
> I still can't get it to work though, even with your suggestions! I > have a fudgy way to work round the problem at the moment but if you or > anyone has any further suggestions I;d be really grateful. If you can describe how your "fudge" differs from the obvious way of doing this, then it might be possible to guess why the obvious way isn't working. -- chris Chris Uppal |
|
![]() |
| Thread Tools | Search this Thread |
|
|
Similar Threads
|
||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| Loading jars for Java Web Start | nhdsl | Software | 0 | 06-17-2009 02:21 PM |
| loading java class from .war file | jayeth | Software | 0 | 04-09-2009 07:06 PM |
| Loading 24,000 rows into C# .net Datagrid | Kagu | Software | 0 | 03-10-2009 06:51 PM |
| Custom Class Loader for Web Application using Tomcat | tapas.adhikary | Software | 0 | 04-22-2008 09:53 AM |
| Error loading Explorer.exe | Jeff Shealey | A+ Certification | 0 | 06-23-2003 01:14 AM |