ClassCastException with URLClassLoader

I’m dynamically loading classes from jar files at runtime with a URLClassLoader. This works fine with this code:

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:

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?

“– 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?

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.

URLClassLoader classLoader = URLClassLoader.newInstance( new URL[] { file.toURI().toURL() } );
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?

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

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

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.

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:

Class A extends B

and then:

Class B implements Mod

Conclusion:

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.

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

Assumes that a no-args constructor exists.

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 :slight_smile:

@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

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
[/quote]
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?

The stack trace would be:

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)

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:

package modkit.mod;

public interface Mod {

	public boolean test();
}
package testmod;

public class NotAModClass {

}
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.

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).