Отражение Java: создайте новый экземпляр интерфейса, предоставив java.lang.ClassCastException

#java #reflection #classloader

#java #отражение #classloader

Вопрос:

У меня есть структура проекта EAR:

EAR

  • TestDependency.jar

    • MyInterface.class;
  • TestEJBModule.jar

    • ExternalObject.class (реализует MyInterface);
  • TestWar

    • SingletonBean
    • MyTestClass (реализует MyInterface);

В одноэлементном компоненте мне нужно динамически создавать класс ExternalObject, используя имя класса, но я получаю

 Caused by: javax.ejb.EJBException: java.lang.ClassCastException: com.bsssrl.testejbmodule.ExternalObject cannot be cast to com.bsssrl.MyInterface
  

Код является:

     Class localclass = Class.forName("com.bsssrl.test.testwar.MyTestClass");
    Object olocal = localclass.newInstance();
    MyInterface local = (MyInterface) olocal;
    LOG.log(Level.INFO, "Test local.getString()   : {0}",local.getString());
    LOG.log(Level.INFO, "Test local.getAlfa()     : {0}",local.getAlfa());


Class exclass = Class.forName("com.bsssrl.testejbmodule.ExternalObject");
Object oex = exclass.newInstance();
if(MyInterface.class.isAssignableFrom(exclass)){
   MyInterface extern = (MyInterface) oex;
   LOG.log(Level.INFO, "Test extern.getString()  : {0}",extern.getString());
   LOG.log(Level.INFO, "Test extern.getAlfa()    : {0}",extern.getAlfa());
}else{
       LOG.log(Level.SEVERE, "Class {0} not implement MyInterface",exclass);
}
  

Класс является:

 public class ExternalObject implements MyInterface{

public Alfa alfa;

@Override
public String getString() {
    return "from external object in EJB module";
}

@Override
public Alfa getAlfa() {
    return alfa;
}

@Override
public void setAlfa(Alfa a) {
    this.alfa = a;
}

}
  

Первый фрагмент кода работает, но второй запускает ClassCastException;
Я полагаю, у меня проблема с classloader.

Как я могу это решить?

PS: я использую wildfly-9.0.2.Final

Комментарии:

1. попробуйте проверить, реализует ли ExternalObject MyInterface.

2. @RayLloy я изменил код в вопросе, добавив проверку … проверка завершается неудачей, даже если ExternalObject реализует MyInterface

3. Я выполнил тот же тест, что и Java-приложение, и ваша проверка работает нормально. Вы уверены, что создали TestEJBModule. jar после модификации?

Ответ №1:

Если вы получаете исключения classcast между совместимыми классами, это всегда означает, что они были загружены разными загрузчиками классов (очень вероятно, поскольку один находится в состоянии ВОЙНЫ, другой в EAR) или что доступно несколько версий класса, и выбирается неправильная (несовместимая). С JBoss / Wildfly последнее особенно легко сделать, поскольку у него испорченная стратегия загрузки классов.

Чтобы проверить первое, попробуйте установить classloader на тот же, который был загружен MyInterface явно:

 Class.forName("com.bsssrl.testejbmodule.ExternalObject", true, MyInterface.class.getClassLoader())
  

Комментарии:

1. Попробовав, я получаю ту же ошибку: ClassLoader clInterfaccia = MyInterface.class.getClassLoader(); localclass = Class.forName(classname, true, clInterfaccia); olocal = localclass.newInstance(); if(MyInterface.class.isAssignableFrom(localclass)) -> false

Ответ №2:

Я получил ClassCastException на

 IService iService=(IService) classS.newInstance();
  

с

 urlClassLoader=URLClassLoader.newInstance(new URL[] {new URL(urlStr)}); 
  

а затем добавьте загрузчик класса в качестве параметра newInstance, и это решило проблему для меня:

 urlClassLoader=URLClassLoader.newInstance(new URL[] {new URL(urlStr)},IService.class.getClassLoader());