ClassCastException при приведении к тому же классу - PullRequest
51 голосов
/ 05 мая 2009

У меня есть 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(), который загружает ранее созданный объект EJB из сеанса (я использую Websphere Portal Server). Когда я пытаюсь преобразовать этот объект обратно в DynamicBean2, происходит сбой с ClassCastException.

Когда я вытаскиваю объект из сеанса, используя

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

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

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

Ответы [ 11 ]

56 голосов
/ 05 мая 2009

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

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

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

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

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

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

12 голосов
/ 05 мая 2009

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

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

2 голосов
/ 25 ноября 2011

У меня возникла проблема 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 находится не в каталоге lib JBoss, а в каталоге lib веб-приложения. Копирование jar в mywebapp / WEB-INF / lib также решило проблему. Другое решение состояло в том, чтобы заблокировать digester.setClassLoader (MyTemplate.class.getClassLoader ()), но в этом контексте это выглядит довольно уродливо.

0 голосов
/ 13 марта 2019

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

Ссылка: Исключение карты бульдозера, связанное с Spring boot devtools

0 голосов
/ 10 августа 2018

Имел то же самое 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, а затем код заработал, как и ожидалось.

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

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

0 голосов
/ 21 июня 2017

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

0 голосов
/ 28 февраля 2017

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

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

0 голосов
/ 21 февраля 2017

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

0 голосов
/ 08 января 2017

У меня была похожая проблема с JAXB и JBoss AS 7.1. Проблема и решение описаны здесь: javax.xml.bind.JAXBException: класс *** или любой из его суперкласса известны этому контексту . Исключением было org.foo.bar.ValueSet, его нельзя преобразовать в org.foo.bar.ValueSet

0 голосов
/ 17 ноября 2014

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

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

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

...