can't cast to implemented interface
Asked Answered
C

2

45

i'm very confused...

I have a class which directly implements an interface:

public class Device implements AutocompleteResult
{...}

Here is proof that I'm looking at the right variables:

Object match = ...;
log.debug(match.getClass()); // Outputs 'Device'
log.debug(match.getClass().getInterfaces()[0]); // Outputs 'AutocompleteResult'

Yet when I try to cast an instance of the class to the interface:

AutocompleteResult result = (AutocompleteResult) match;

I get a ClassCastException!

ClassCastException: Device cannot be cast to AutocompleteResult

Also, isAssignableFrom returns false and i'm not sure why:

log.debug(AutocompleteResult.class.isAssignableFrom(Device.class));

from the doc:

Determines if the class or interface represented by this Class object is either the same as, or is a superclass or superinterface of, the class or interface represented by the specified Class parameter.

Shouldn't I always be able to cast a object to an interface its class implements?

Thanks.

Cretic answered 7/11, 2011 at 11:32 Comment(1)
Yes, you should! (and you shouldn't even need the explicit cast.) Please post some self-contained example code that demonstrates the problem.Melodymeloid
G
74

This can happen if two different classloaders load a class named AutocompleteResult.

These two classes are then treated as entirely different classes, even if they have the same package and name (and even implementation/fields/methods).

A common cause for this is if you use some kind of plugin system and both your base classes and the plugin classes provide the same class.

To check for this issue print the value returned by Class.getClassLoader() on both offending classes (i.e. the class of the interface implemented by Device and the result of AutocompleteResult.class).

Glosseme answered 7/11, 2011 at 11:36 Comment(3)
wow, thanks! i was literally tearing hair out on this one. i will try to resolve the classloading issue now...Cretic
+1: Try log.debug(match.getClass().getInterfaces()[0].getClassLoader()); log.debug(AutocompleteResult.class.getClassLoader())Certitude
My issue was that i had the wrong imported class and this helped me determine that : Class[] interfaces = match.getClass().getInterfaces(); for(int i = 0; i < interfaces.length; i++){ Log.d(DEBUG_TAG, interfaces[i].toString()); Log.d(DEBUG_TAG, AutocompleteResult.class.toString()); } Hersh
L
1

AKA when Java apparently doesn't Java.

I hit this problem recently with Play Framework 2.6.3, what helped me was this: https://www.playframework.com/documentation/2.6.x/ThreadPools#Application-class-loader

I leave this info here for the people that might have the same problem.

To make it clearer, what helps is:

Injecting Application on an Eager Singleton and then using its classloader to load the classes I was having issues with.

To make it clearer

public class Module {


 @Override
 public void configure {
   bind(TheClassLoaderLoader.class).asEagerSingleton()

public static class TheClassLoaderLoader {
  @Inject
        public TheClassLoaderLoader( Application application) {

         ClassLoader classloader = application.classloader();

                Class<?> interfaceClass = classloader.loadClass(InterfaceClass.class.getName());
                classloader.loadClass(ImplementsInterfaceClass.class.getName()).asSubclass(interfaceClass);

The example here https://playframework.com/documentation/2.6.x/JavaDependencyInjection#Configurable-bindings

That uses Environment often throws a frustrating ClassNotFoundException

Cheers

Liberati answered 16/10, 2017 at 21:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.