Подтвердить что ты не робот

ClassCastException при литье в один класс

У меня есть два разных 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.

Любая причина, по которой я получаю это?

4b9b3361

Ответ 1

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

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

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

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

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

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

Ответ 2

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

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

Ответ 3

У меня возникла проблема с 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
}

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

Ответ 4

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

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

EDIT: я отредактировал файл 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

Ответ 5

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

Скопируйте все org.eclipse.persistence jar файлы с glassfish4/glassfish/modules на WEB-INF/lib. Затем зайдите в glassfish-web.xml и установите class-delegate на false.

Работал для меня!

Ответ 7

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

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

public interface DocumentStoreService {

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

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

EJB bean:

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

Правильная обертка spring вокруг 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, и он найдет локальный интерфейс просто прекрасным, а также будет выполнять методы без каких-либо проблем (из отдельного приложения в одном контейнере), но объекты модели не маршалируются и загружаются из другого загрузчика классов, если вы используете локальный интерфейс по ошибке.

Ответ 8

Другая опция:

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

Ответ 9

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

Ответ 10

Если бы тот же 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, повторно развернул WAR, а затем код my.war/WEB-INF/lib как и ожидалось.

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

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

Ответ 11

Я получил эту проблему после добавления зависимости к spring-boot-devtools в моем проекте Springboot. Я удалил зависимость, и проблема ушла. Мое лучшее предположение на данный момент состоит в том, что spring-boot-devtools вводит новый загрузчик классов, и это вызывает проблему проблем приведения классов между различными загрузчиками классов в определенных случаях, когда новый загрузчик классов не используется некоторыми потоками.

Ссылка: исключение карты dozer, связанное с Spring boot devtools