ClassCastException при приведении к тому же классу

у меня есть 2 разных проекта Java, один имеет 2 класса:dynamicbeans.DynamicBean2 и dynamic.Validator.

в другом проекте я загружаю оба этих класса динамически и сохраняю их на Object

class Form {
    Class beanClass;
    Class validatorClass;
    Validator validator;
}

затем я иду вперед и создаю Validator объект с помощью validatorClass.newInstance() на validator затем я создаю объект bean, а также используя beanClass.newInstance() и добавьте его в сеанс.

portletRequest.setAttribute("DynamicBean2", bean);

в течение жизненного цикла Form проект, я вызываю validator.validate() который загружает ранее созданный объект bean из сеанса (я запускаю Websphere Portal Server). Когда я пытаюсь вернуть этот объект в DynamicBean2 он терпит неудачу с ClassCastException.

когда я вытаскиваю объект из сеанса с помощью

faces.getApplication().createValueBinding("#{DynamicBean2}").getValue(faces);

и проверьте класс его с помощью .getClass() Я dynamicbeans.DynamicBean2. Это класс, в который я хочу бросить его, однако, когда я пытаюсь получить ClassCastException.

почему я получаю это?

10 ответов


Я не совсем следую вашему описанию потока программы, но обычно, когда вы получаете ClassCastExceptions вы не можете объяснить, что вы загрузили класс с одним загрузчиком классов, затем попробуйте привести его к тому же классу, загруженному другим загрузчиком классов. Это не сработает - они представлены двумя различными объектами класса внутри JVM, и приведение завершится неудачей.

есть статья о загрузке классов в WebSphere. Я не могу сказать, как он относится к приложение, но есть ряд возможных решений. Я могу думать, по крайней мере:

  1. измените загрузчик классов контекста вручную. Требуется, чтобы вы действительно могли получить ссылку на соответствующий загрузчик классов, что может быть невозможно в вашем случае.

    Thread.currentThread().setContextClassloader(...);
    
  2. убедитесь, что класс будет загружен загрузчиком класса выше в иерархии.

  3. сериализация и десериализация объекта. (Фу!)

существует, вероятно,более подходящий способ для вашей конкретной ситуации.


объекты класса были загружены разными загрузчиками классов, поэтому экземпляры, созданные в каждом из классов рассматриваются как "несовместимые". Это распространенная проблема в среде, где используется множество различных загрузчиков классов и передаются объекты. Эти проблемы могут легко возникнуть в средах Java EE и portal.

приведение экземпляра класса требует, чтобы класс, связанный с кастуемым объектом, был таким же, как и загруженный текущий контекст потока classloader.


Я получил проблему A2AClassCastException при попытке создать список объектов из XML с помощью Apache Commons Digester.

List<MyTemplate> templates = new ArrayList<MyTemplate>();
Digester digester = new Digester();
digester.addObjectCreate("/path/to/template", MyTemplate.class);
digester.addSetNext("/path/to/template", "add");
// Set more rules...
digester.parse(f); // f is a pre-defined File

for(MyTemplate t : templates) { // ClassCastException: Cannot cast mypackage.MyTemplate to mypackage.MyTemplate
    // Do stuff
}

как указано выше, причина в том, что digester не использует тот же загрузчик классов, что и остальная часть программы. Я запустил это в JBoss, и оказалось, что commons-digester.jar не был в каталоге lib JBoss, а скорее в каталоге lib веб-приложения. Копирование jar в mywebapp/WEB-INF / lib также решило проблему. Другим решением было casll метантенка.setClassLoader(шаблон mytemplate.класс.getClassLoader ()), но в этом контексте это кажется довольно уродливым решением.


У меня была такая же проблема с поиском EJB из другого EJB. Я решил добавить @Remote (MyInterface.class) для конфигурации класса EJB


У меня была та же проблема при использовании нескольких экземпляров JBoss на разных машинах. Плохо, что я не наткнулся на этот пост раньше.
На разных машинах были развернуты артефакты, два из них объявили загрузчики классов с одинаковыми именами.Я изменил одно из имен загрузчика классов, и все работало нормально = > остерегайтесь копирования и вставки!

почему в ClassCastException не упоминается задействованные загрузчики классов? - Думаю, это будет очень полезная информация.
Кто-нибудь знает, будет ли что-то подобное доступно в будущем? Необходимость проверки загрузчиков класса 20-30 артефактов не так уж приятна. Или есть что-то, что я пропустил в тексте исключения?

редактировать: я редактировал META-INF / jboss-app.xml-файл и изменил имя загрузчика, идея состоит в том, чтобы иметь уникальное имя. На работе мы используем идентификатор артефакта(уникальный) в сочетании с версией, вставленной maven ({$version}) во время сборки.
используя динамические поля являются необязательными, но помогают при развертывании разных версий одного и того же приложения.

<jboss-app>
   <loader-repository> 
   com.example:archive=unique-archive-name-{$version}
   </loader-repository> 
</jboss-app>

вы можете найти некоторую информацию здесь:https://community.jboss.org/wiki/ClassLoadingConfiguration


у меня была та же проблема, и я, наконец, нашел обходной путь java.net :

скопировать все org.eclipse.persistence jar файлы glassfish4/glassfish/modules to WEB-INF/lib. Тогда иди в свой glassfish-web.xml и set class-delegate до false.

работал на меня !


У меня была аналогичная проблема с JAXB и JBoss как 7.1. Проблема и решение описаны здесь: javax.XML.связывать.JAXBException: Class *** ни один из его суперкласса не известен этому контексту. Исключение, которое было дано, было org.foo.бар.Набор значений не может быть приведен в организацию.foo.бар.Valueset с


у меня была такая же проблема на wildfly EJB, EJB возвращал список объектов и имел удаленный и локальный интерфейс. Я использовал локальный интерфейс по ошибке, что работало просто отлично, пока вы не попытаетесь бросить объекты в списке.

локальный удаленный интерфейс/:

public interface DocumentStoreService {

    @javax.ejb.Remote
    interface Remote extends DocumentStoreService {
    }

    @javax.ejb.Local
    interface Local extends DocumentStoreService {
    }

Боб EJB:

@Stateless
public class DocumentStoreServiceImpl implements DocumentStoreService.Local, DocumentStoreService.Remote {

правильная обертка пружины вокруг EJB:

<bean id="documentStoreService" class="org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean">
    <property name="jndiName" value="java:global/dpc/dpc-ejb/DocumentStoreServiceImpl!santam.apps.dpc.service.DocumentStoreService$Remote"/>
    <property name="businessInterface" value="santam.apps.dpc.service.DocumentStoreService$Remote"/>
    <property name="resourceRef" value="true" />
</bean>

обратите внимание на $ Remote, вы можете изменить это на $Local, и это будет найти локальный интерфейс просто отлично, а также выполнить методы без каких-либо проблем (из отдельного приложения на том же контейнере), но объекты модели не маршалируются и из другого загрузчика классов, если вы используете локальный интерфейс по ошибке.


другой вариант:

случилось со мной в weblogic, но я думаю, что это может произойти и на других серверах, если вы (просто) "опубликуете", и поэтому некоторые из ваших классов будут повторно загружены. Вместо этого сделайте "Clean", чтобы все классы были повторно загружены вместе.


было то же самое my.package.MyClass cannot be cast to my.package.MyClass на WildFly 10.1 и, как я понимаю, я сделал противоположное тому, что @ Emil Lundberg описал в своем ответе.

я добавил модуль (который содержит my.package.MyClass) к my.war/WEB-INF/jboss-deployment-structure.xml в зависимости

<dependencies>
    ...
    <module name="my.package"/>
</dependencies>

и удалены соответствующие jar С my.war/WEB-INF/lib, повторно развернул войну, а затем код работал, как ожидалось.

таким образом, мы убедились, что это решает проблему. Теперь нам нужно убедиться, что проблема не вернется, например, когда обновленная версия войны будет собран и развернут.

для этого, в источниках тех войны, требуется добавить <scope>provided</scope> для тех jar на pom.xml, так что когда my.war повторно собирается в следующий раз с введенным кодом исправления/улучшения, он не будет связывать это jar на my.war/WEB-INF/lib.