Java-Gaming.org Hi !
Featured games (91)
games approved by the League of Dukes
Games in Showcase (762)
Games in Android Showcase (229)
games submitted by our members
Games in WIP (846)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  ClassCastException with URLClassLoader  (Read 550 times)
0 Members and 1 Guest are viewing this topic.
Offline DesertCoockie
« Posted 2018-07-05 21:28:20 »

I'm dynamically loading classes from jar files at runtime with a URLClassLoader. This works fine with this code:
1  
2  
3  
Class<?> clazz = classLoader.loadClass( className );
Constructor<?> constructor = clazz.getConstructor();
createdObject = (Mod)constructor.newInstance();

But there is the problem of encountering a class that does not implement Mod and thus causes a class cast exception. I'm trying to get around this by checking before creating the object, if the loaded class implements Mod; I've tried:
1  
2  
3  
4  
5  
if(Mod.class.isAssignableFrom( clazz )) { ... } // 1st
if(clazz instanceof Mod) { ... } // 2nd
for( Class<?> interf : implInterfaces ) { // 3rd
   if(interf.getName().equals( Mod.class.getName() )) { ... }
}

But all of these throw their own ClassCastException.

Is there any way around this limitation?
Offline ByerN
« Reply #1 - Posted 2018-07-05 21:55:12 »

https://techblug.wordpress.com/2012/03/17/classloader-tips/

"– Siblings classloaders (two classloaders who are in each other’s hierarchy) can load the same class independently, possibly from the same location. In that case the two classes are different from the JVM point of view. As a consequence casting an instance of this class from one of the classloader to the class from the other will result in a ClassCastException (error messages will show the exact same name but the classes are different!)."

I think it's about it. Solution is to use class from the same classloader. Or some generic solution like checking class via string or smthng (dirty one). Or use only one classloader?
Offline DesertCoockie
« Reply #2 - Posted 2018-07-06 06:44:53 »

https://techblug.wordpress.com/2012/03/17/classloader-tips/

Solution is to use class from the same classloader. Or some generic solution like checking class via string or smthng (dirty one). Or use only one classloader?
How would you go about that? I cannot really see where I'm using classes from a different class loader.
Where am I using 2 class loaders? Does Constructor qualify as a second class loader?
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Abuse

JGO Ninja


Medals: 68


falling into the abyss of reality


« Reply #3 - Posted 2018-07-06 11:05:58 »

https://techblug.wordpress.com/2012/03/17/classloader-tips/

Solution is to use class from the same classloader. Or some generic solution like checking class via string or smthng (dirty one). Or use only one classloader?
How would you go about that? I cannot really see where I'm using classes from a different class loader.
Where am I using 2 class loaders? Does Constructor qualify as a second class loader?

Show us how you're constructing the URLClassLoader.
Offline DesertCoockie
« Reply #4 - Posted 2018-07-06 12:26:11 »

Show us how you're constructing the URLClassLoader.
1  
URLClassLoader classLoader = URLClassLoader.newInstance( new URL[] { file.toURI().toURL() } );
Offline Abuse

JGO Ninja


Medals: 68


falling into the abyss of reality


« Reply #5 - Posted 2018-07-06 13:32:29 »

1)
1  
if(Mod.class.isAssignableFrom( clazz )) { ... } // 1st

This should work, moreover it shouldn't be possible for it to throw a ClassCastException.
Your code example seems to indicate that you might have an Exception block catching a whole host of Exceptions.
Are you sure this line is the source of the Exception?

2)
1  
if(clazz instanceof Mod) { ... } // 2nd

This is incorrect (clazz is always an instance of java.lang.Class); for your code example you'd want:

1  
if(createdObject instanceof Mod) { ... }

However as previously mentioned, isAssignableFrom is the correct (more efficient & safer) approach as it performs the type check without requiring instantiation.

3)
1  
2  
3  
for( Class<?> interf : implInterfaces ) { // 3rd
   if(interf.getName().equals( Mod.class.getName() )) { ... }
}

I'd advise against doing this; it's fragile code.
I'm fairly sure it would break if you had something like:

1  
Class A extends B

and then:
1  
Class B implements Mod


Conclusion:

1  
2  
Constructor<?> constructor = clazz.getConstructor();
createdObject = (Mod)constructor.newInstance();


Each of these lines should be wrapped in individual Exception blocks, as they make assumptions about the subclasses of Mod that might not be true, and need to be handled appropriately.

1  
Constructor<?> constructor = clazz.getConstructor();

Assumes that a no-args constructor exists.

1  
createdObject = (Mod)constructor.newInstance();

Assumes that this constructor is accessible (public), and instantiable (not abstract).


Thus the cause of your problem might be a class that *does* implement the Mod interface, but fails because it lacks a public & no args constructor.
This failure (either a NoSuchMethodException, InstantiationException or IllegalAccessException) might then be getting caught by a blanket catch, and misinterpreted as a ClassCastException.

I'd suggest a more complete code listing so we can diagnose the problem without the speculative guessing I've made Smiley
Offline DesertCoockie
« Reply #6 - Posted 2018-07-06 16:57:17 »

@Abuse
1) Yes, this line is the source of the exception. All other lines execute fine.
2) This defeats the purpose, because I need to check if clazz extends Mod before I create an object.
3) Was really just because I was desperate  persecutioncomplex

There exists no no-args constructor, that's why I use getConstructor(), it works for all constructors. And yes, the constructor is public.
Also, the whole class loading works flawlessly with classes that extend Mod and have the multiple-args constructor. The object get's created and is usable.
I'll put my code into a code bucket... https://paste.ofcode.org/8LUA2EC5pXMcECCtNtnLQu
Offline Abuse

JGO Ninja


Medals: 68


falling into the abyss of reality


« Reply #7 - Posted 2018-07-06 19:56:26 »

2) This defeats the purpose, because I need to check if clazz extends Mod before I create an object.

My point was that your code was erroneous; in your example clazz is always an instance of java.lang.Class.
Thus "clazz instanceof Mod" will always be false.
It's not particularly relevant though, as you should definitely be using isAssignableFrom.

Quote
There exists no no-args constructor, that's why I use getConstructor(), it works for all constructors. And yes, the constructor is public.
Also, the whole class loading works flawlessly with classes that extend Mod and have the multiple-args constructor. The object get's created and is usable.
I'll put my code into a code bucket... https://paste.ofcode.org/8LUA2EC5pXMcECCtNtnLQu

getConstructor(...) returns the constructor matching the "..." type parameters; as you aren't providing any type parameters, the constructor being returned is (and can only ever be) the no-args constructor.

I can't see anything obviously wrong with what you put in code bucket.
Can you post the stack trace of the Exception?
Offline DesertCoockie
« Reply #8 - Posted 2018-07-07 11:37:51 »

The stack trace would be:
1  
2  
3  
4  
5  
Exception in thread "main" java.lang.ClassCastException: testmod.NotAModClass cannot be cast to modkit.mod.Mod
   at modkit.ModLoader.makeObjectFromClass(ModLoader.java:68)
   at modkit.ModLoader.loadJarFile(ModLoader.java:43)
   at modkit.ModLoader.loadMods(ModLoader.java:14)
   at main.MainApp.main(MainApp.java:39)

(line numbers changed to match the pasted code)
Offline Abuse

JGO Ninja


Medals: 68


falling into the abyss of reality


« Reply #9 - Posted 2018-07-07 19:46:14 »

Those line numbers don't align with the code you've posted to ofCode

However I've run your code, and with a trivial implementation of NotAModClass & AModClass, it works perfectly. (loading & returning AModClass, and ignoring NotAModClass).

Trivial implementation:

1  
2  
3  
4  
5  
6  
package modkit.mod;

public interface Mod {

   public boolean test();
}

1  
2  
3  
4  
5  
package testmod;

public class NotAModClass {

}


1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
package testmod;

import modkit.mod.Mod;

public class AModClass implements Mod {

   @Override
   public boolean test() {
      return true;
   }

}


Does the jar you're loading your Mod subclasses from contain a copy of modkit.mod.Mod.class?
It shouldn't cause a conflict (as the URLClassLoader should delegate to its parent ClassLoader when attempting to resolve references to this class), but without testing it I can't be 100% sure.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline DesertCoockie
« Reply #10 - Posted 2018-07-08 15:06:14 »

Does the jar you're loading your Mod subclasses from contain a copy of modkit.mod.Mod.class?
It does not. The class Mod is within the mod kit package, the same as my mod loader class, the code is from.
Also, on my screen, the line numbers align (double checked; don't really know what's going on there).
Pages: [1]
  ignore  |  Print  
 
 

 
EgonOlsen (361 views)
2018-06-10 19:43:48

EgonOlsen (363 views)
2018-06-10 19:43:44

EgonOlsen (300 views)
2018-06-10 19:43:20

DesertCoockie (535 views)
2018-05-13 18:23:11

nelsongames (866 views)
2018-04-24 18:15:36

nelsongames (847 views)
2018-04-24 18:14:32

ivj94 (1295 views)
2018-03-24 14:47:39

ivj94 (418 views)
2018-03-24 14:46:31

ivj94 (1080 views)
2018-03-24 14:43:53

Solater (430 views)
2018-03-17 05:04:08
Java Gaming Resources
by philfrei
2017-12-05 19:38:37

Java Gaming Resources
by philfrei
2017-12-05 19:37:39

Java Gaming Resources
by philfrei
2017-12-05 19:36:10

Java Gaming Resources
by philfrei
2017-12-05 19:33:10

List of Learning Resources
by elect
2017-03-13 14:05:44

List of Learning Resources
by elect
2017-03-13 14:04:45

SF/X Libraries
by philfrei
2017-03-02 08:45:19

SF/X Libraries
by philfrei
2017-03-02 08:44:05
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!