Reflection - Class Loading and NoClassDefFoundError

Discussion in 'Java' started by lee@datadialogs.com, Jul 24, 2006.

  1. Guest

    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.
     
    , Jul 24, 2006
    #1
    1. Advertising

  2. Guest

    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
     
    , Jul 24, 2006
    #2
    1. Advertising

  3. Lee Guest

    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, Jul 25, 2006
    #3
  4. Chris Uppal Guest

    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, Jul 25, 2006
    #4
  5. Lee Guest

    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, Jul 25, 2006
    #5
  6. Lee Guest

    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, Jul 25, 2006
    #6
  7. Lee Guest

    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, Jul 25, 2006
    #7
  8. Chris Uppal Guest

    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, Jul 25, 2006
    #8
  9. Lee Guest


    > 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, Jul 25, 2006
    #9
  10. Chris Uppal Guest

    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, Jul 26, 2006
    #10
  11. Lee Guest

    Cheers for your assistance - I've managed to sort the
    NoClassDefFoundError - I think. Some serious testing is needed first!

    I do now have a new exception, but I'll come to that in a different
    thread if necessary!

    Thanks again folks.

    Lee.

    Chris Uppal wrote:
    > 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
     
    Lee, Jul 27, 2006
    #11
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. qazmlp
    Replies:
    6
    Views:
    13,461
    Joseph Millar
    Jul 11, 2003
  2. veovis
    Replies:
    3
    Views:
    700
    Roedy Green
    Apr 7, 2004
  3. Julian
    Replies:
    1
    Views:
    712
    Roland
    May 24, 2005
  4. Replies:
    1
    Views:
    2,163
    Irmen de Jong
    Jun 22, 2004
  5. cmckenzie
    Replies:
    1
    Views:
    364
    Dave Angel
    Dec 1, 2009
Loading...

Share This Page